Completed
Push — ezp-30882-thumbnail ( 274ed9...d4335b )
by
unknown
14:43
created

testCreateContentThrowsUnauthorizedException()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 56

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 56
rs 8.9599
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(): void
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
        $permissionResolverMock = $this->getPermissionResolverMock();
81
        $settings = ['default_version_archive_limit' => 10];
82
83
        $service = new ContentService(
0 ignored issues
show
Unused Code introduced by
$service 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...
84
            $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...
85
            $persistenceHandlerMock,
86
            $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...
87
            $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...
88
            $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...
89
            $fieldTypeRegistryMock,
90
            $permissionResolverMock,
91
            $settings
92
        );
93
    }
94
95
    /**
96
     * Test for the loadVersionInfo() method, of published version.
97
     *
98
     * @covers \eZ\Publish\Core\Repository\ContentService::loadVersionInfoById
99
     */
100
    public function testLoadVersionInfoById()
101
    {
102
        $contentServiceMock = $this->getPartlyMockedContentService(['loadContentInfo']);
103
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandler */
104
        $contentHandler = $this->getPersistenceMock()->contentHandler();
105
        $domainMapperMock = $this->getDomainMapperMock();
106
        $versionInfoMock = $this->createMock(APIVersionInfo::class);
107
        $permissionResolver = $this->getPermissionResolverMock();
108
109
        $versionInfoMock->expects($this->once())
110
            ->method('isPublished')
111
            ->willReturn(true);
112
113
        $contentServiceMock->expects($this->never())
114
            ->method('loadContentInfo');
115
116
        $contentHandler->expects($this->once())
117
            ->method('loadVersionInfo')
118
            ->with(
119
                $this->equalTo(42),
120
                $this->equalTo(null)
121
            )->will(
122
                $this->returnValue(new SPIVersionInfo())
123
            );
124
125
        $domainMapperMock->expects($this->once())
126
            ->method('buildVersionInfoDomainObject')
127
            ->with(new SPIVersionInfo())
128
            ->will($this->returnValue($versionInfoMock));
129
130
        $permissionResolver->expects($this->once())
131
            ->method('canUser')
132
            ->with(
133
                $this->equalTo('content'),
134
                $this->equalTo('read'),
135
                $this->equalTo($versionInfoMock)
136
            )->will($this->returnValue(true));
137
138
        $result = $contentServiceMock->loadVersionInfoById(42);
139
140
        $this->assertEquals($versionInfoMock, $result);
141
    }
142
143
    /**
144
     * Test for the loadVersionInfo() method, of a draft.
145
     *
146
     * @depends testLoadVersionInfoById
147
     * @covers \eZ\Publish\Core\Repository\ContentService::loadVersionInfoById
148
     */
149
    public function testLoadVersionInfoByIdAndVersionNumber()
150
    {
151
        $permissionResolver = $this->getPermissionResolverMock();
152
        $contentServiceMock = $this->getPartlyMockedContentService(['loadContentInfo']);
153
        /** @var \PHPUnit_Framework_MockObject_MockObject $contentHandler */
154
        $contentHandler = $this->getPersistenceMock()->contentHandler();
155
        $domainMapperMock = $this->getDomainMapperMock();
156
        $versionInfoMock = $this->createMock(APIVersionInfo::class);
157
158
        $versionInfoMock->expects($this->any())
159
            ->method('__get')
160
            ->with('status')
161
            ->willReturn(APIVersionInfo::STATUS_DRAFT);
162
163
        $contentServiceMock->expects($this->never())
164
            ->method('loadContentInfo');
165
166
        $contentHandler->expects($this->once())
167
            ->method('loadVersionInfo')
168
            ->with(
169
                $this->equalTo(42),
170
                $this->equalTo(2)
171
            )->willReturn(new SPIVersionInfo());
172
173
        $domainMapperMock->expects($this->once())
174
            ->method('buildVersionInfoDomainObject')
175
            ->with(new SPIVersionInfo())
176
            ->willReturn($versionInfoMock);
177
178
        $permissionResolver->expects($this->once())
179
            ->method('canUser')
180
            ->with(
181
                $this->equalTo('content'),
182
                $this->equalTo('versionread'),
183
                $this->equalTo($versionInfoMock)
184
            )->willReturn(true);
185
186
        $result = $contentServiceMock->loadVersionInfoById(42, 2);
187
188
        $this->assertEquals($versionInfoMock, $result);
189
    }
190
191
    /**
192
     * Test for the loadVersionInfo() method.
193
     *
194
     * @covers \eZ\Publish\Core\Repository\ContentService::loadVersionInfoById
195
     */
196
    public function testLoadVersionInfoByIdThrowsNotFoundException()
197
    {
198
        $this->expectException(\eZ\Publish\Core\Base\Exceptions\NotFoundException::class);
199
200
        $contentServiceMock = $this->getPartlyMockedContentService(['loadContentInfo']);
201
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandler */
202
        $contentHandler = $this->getPersistenceMock()->contentHandler();
203
204
        $contentHandler->expects($this->once())
205
            ->method('loadVersionInfo')
206
            ->with(
207
                $this->equalTo(42),
208
                $this->equalTo(24)
209
            )->will(
210
                $this->throwException(
211
                    new NotFoundException(
212
                        'Content',
213
                        [
214
                            'contentId' => 42,
215
                            'versionNo' => 24,
216
                        ]
217
                    )
218
                )
219
            );
220
221
        $contentServiceMock->loadVersionInfoById(42, 24);
222
    }
223
224
    /**
225
     * Test for the loadVersionInfo() method.
226
     *
227
     * @covers \eZ\Publish\Core\Repository\ContentService::loadVersionInfoById
228
     */
229
    public function testLoadVersionInfoByIdThrowsUnauthorizedExceptionNonPublishedVersion()
230
    {
231
        $this->expectException(\eZ\Publish\Core\Base\Exceptions\UnauthorizedException::class);
232
233
        $contentServiceMock = $this->getPartlyMockedContentService();
234
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandler */
235
        $contentHandler = $this->getPersistenceMock()->contentHandler();
236
        $domainMapperMock = $this->getDomainMapperMock();
237
        $versionInfoMock = $this->createMock(APIVersionInfo::class);
238
        $permissionResolver = $this->getPermissionResolverMock();
239
240
        $versionInfoMock->expects($this->any())
241
            ->method('isPublished')
242
            ->willReturn(false);
243
244
        $contentHandler->expects($this->once())
245
            ->method('loadVersionInfo')
246
            ->with(
247
                $this->equalTo(42),
248
                $this->equalTo(24)
249
            )->will(
250
                $this->returnValue(new SPIVersionInfo())
251
            );
252
253
        $domainMapperMock->expects($this->once())
254
            ->method('buildVersionInfoDomainObject')
255
            ->with(new SPIVersionInfo())
256
            ->will($this->returnValue($versionInfoMock));
257
258
        $permissionResolver->expects($this->once())
259
            ->method('canUser')
260
            ->with(
261
                $this->equalTo('content'),
262
                $this->equalTo('versionread'),
263
                $this->equalTo($versionInfoMock)
264
            )->will($this->returnValue(false));
265
266
        $contentServiceMock->loadVersionInfoById(42, 24);
267
    }
268
269
    /**
270
     * Test for the loadVersionInfo() method.
271
     *
272
     * @covers \eZ\Publish\Core\Repository\ContentService::loadVersionInfoById
273
     */
274 View Code Duplication
    public function testLoadVersionInfoByIdPublishedVersion()
275
    {
276
        $contentServiceMock = $this->getPartlyMockedContentService();
277
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandler */
278
        $contentHandler = $this->getPersistenceMock()->contentHandler();
279
        $domainMapperMock = $this->getDomainMapperMock();
280
        $versionInfoMock = $this->createMock(APIVersionInfo::class);
281
        $permissionResolver = $this->getPermissionResolverMock();
282
283
        $versionInfoMock->expects($this->once())
284
            ->method('isPublished')
285
            ->willReturn(true);
286
287
        $contentHandler->expects($this->once())
288
            ->method('loadVersionInfo')
289
            ->with(
290
                $this->equalTo(42),
291
                $this->equalTo(24)
292
            )->will(
293
                $this->returnValue(new SPIVersionInfo())
294
            );
295
296
        $domainMapperMock->expects($this->once())
297
            ->method('buildVersionInfoDomainObject')
298
            ->with(new SPIVersionInfo())
299
            ->will($this->returnValue($versionInfoMock));
300
301
        $permissionResolver->expects($this->once())
302
            ->method('canUser')
303
            ->with(
304
                $this->equalTo('content'),
305
                $this->equalTo('read'),
306
                $this->equalTo($versionInfoMock)
307
            )->will($this->returnValue(true));
308
309
        $result = $contentServiceMock->loadVersionInfoById(42, 24);
310
311
        $this->assertEquals($versionInfoMock, $result);
312
    }
313
314
    /**
315
     * Test for the loadVersionInfo() method.
316
     *
317
     * @covers \eZ\Publish\Core\Repository\ContentService::loadVersionInfoById
318
     */
319 View Code Duplication
    public function testLoadVersionInfoByIdNonPublishedVersion()
320
    {
321
        $contentServiceMock = $this->getPartlyMockedContentService();
322
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandler */
323
        $contentHandler = $this->getPersistenceMock()->contentHandler();
324
        $domainMapperMock = $this->getDomainMapperMock();
325
        $versionInfoMock = $this->createMock(APIVersionInfo::class);
326
        $permissionResolver = $this->getPermissionResolverMock();
327
328
        $versionInfoMock->expects($this->once())
329
            ->method('isPublished')
330
            ->willReturn(false);
331
332
        $contentHandler->expects($this->once())
333
            ->method('loadVersionInfo')
334
            ->with(
335
                $this->equalTo(42),
336
                $this->equalTo(24)
337
            )->will(
338
                $this->returnValue(new SPIVersionInfo())
339
            );
340
341
        $domainMapperMock->expects($this->once())
342
            ->method('buildVersionInfoDomainObject')
343
            ->with(new SPIVersionInfo())
344
            ->will($this->returnValue($versionInfoMock));
345
346
        $permissionResolver->expects($this->once())
347
            ->method('canUser')
348
            ->with(
349
                $this->equalTo('content'),
350
                $this->equalTo('versionread'),
351
                $this->equalTo($versionInfoMock)
352
            )->will($this->returnValue(true));
353
354
        $result = $contentServiceMock->loadVersionInfoById(42, 24);
355
356
        $this->assertEquals($versionInfoMock, $result);
357
    }
358
359
    /**
360
     * Test for the loadVersionInfo() method.
361
     *
362
     * @covers \eZ\Publish\Core\Repository\ContentService::loadVersionInfo
363
     * @depends eZ\Publish\Core\Repository\Tests\Service\Mock\ContentTest::testLoadVersionInfoById
364
     * @depends eZ\Publish\Core\Repository\Tests\Service\Mock\ContentTest::testLoadVersionInfoByIdThrowsNotFoundException
365
     * @depends eZ\Publish\Core\Repository\Tests\Service\Mock\ContentTest::testLoadVersionInfoByIdThrowsUnauthorizedExceptionNonPublishedVersion
366
     * @depends eZ\Publish\Core\Repository\Tests\Service\Mock\ContentTest::testLoadVersionInfoByIdPublishedVersion
367
     * @depends eZ\Publish\Core\Repository\Tests\Service\Mock\ContentTest::testLoadVersionInfoByIdNonPublishedVersion
368
     */
369
    public function testLoadVersionInfo()
370
    {
371
        $contentServiceMock = $this->getPartlyMockedContentService(
372
            ['loadVersionInfoById']
373
        );
374
        $contentServiceMock->expects(
375
            $this->once()
376
        )->method(
377
            'loadVersionInfoById'
378
        )->with(
379
            $this->equalTo(42),
380
            $this->equalTo(7)
381
        )->will(
382
            $this->returnValue('result')
383
        );
384
385
        $result = $contentServiceMock->loadVersionInfo(
386
            new ContentInfo(['id' => 42]),
387
            7
388
        );
389
390
        $this->assertEquals('result', $result);
391
    }
392
393
    public function testLoadContent()
394
    {
395
        $contentService = $this->getPartlyMockedContentService(['internalLoadContent']);
396
        $content = $this->createMock(APIContent::class);
397
        $versionInfo = $this->createMock(APIVersionInfo::class);
398
        $permissionResolver = $this->getPermissionResolverMock();
399
400
        $content
401
            ->expects($this->once())
402
            ->method('getVersionInfo')
403
            ->will($this->returnValue($versionInfo));
404
        $versionInfo
405
            ->expects($this->once())
406
            ->method('isPublished')
407
            ->willReturn(true);
408
        $contentId = 123;
409
        $contentService
410
            ->expects($this->once())
411
            ->method('internalLoadContent')
412
            ->with($contentId)
413
            ->will($this->returnValue($content));
414
415
        $permissionResolver
416
            ->expects($this->once())
417
            ->method('canUser')
418
            ->with('content', 'read', $content)
419
            ->will($this->returnValue(true));
420
421
        $this->assertSame($content, $contentService->loadContent($contentId));
422
    }
423
424 View Code Duplication
    public function testLoadContentNonPublished()
425
    {
426
        $contentService = $this->getPartlyMockedContentService(['internalLoadContent']);
427
        $content = $this->createMock(APIContent::class);
428
        $versionInfo = $this->createMock(APIVersionInfo::class);
429
        $permissionResolver = $this->getPermissionResolverMock();
430
431
        $content
432
            ->expects($this->once())
433
            ->method('getVersionInfo')
434
            ->will($this->returnValue($versionInfo));
435
        $contentId = 123;
436
        $contentService
437
            ->expects($this->once())
438
            ->method('internalLoadContent')
439
            ->with($contentId)
440
            ->will($this->returnValue($content));
441
442
        $permissionResolver
443
            ->expects($this->exactly(2))
444
            ->method('canUser')
445
            ->will(
446
                $this->returnValueMap(
447
                    [
448
                        ['content', 'read', $content, [], true],
449
                        ['content', 'versionread', $content, [], true],
450
                    ]
451
                )
452
            );
453
454
        $this->assertSame($content, $contentService->loadContent($contentId));
455
    }
456
457
    public function testLoadContentUnauthorized()
458
    {
459
        $this->expectException(\eZ\Publish\Core\Base\Exceptions\UnauthorizedException::class);
460
461
        $permissionResolver = $this->getPermissionResolverMock();
462
463
        $contentService = $this->getPartlyMockedContentService(['internalLoadContent']);
464
        $content = $this->createMock(APIContent::class);
465
        $contentId = 123;
466
        $contentService
467
            ->expects($this->once())
468
            ->method('internalLoadContent')
469
            ->with($contentId)
470
            ->will($this->returnValue($content));
471
472
        $permissionResolver
473
            ->expects($this->once())
474
            ->method('canUser')
475
            ->with('content', 'read', $content)
476
            ->will($this->returnValue(false));
477
478
        $contentService->loadContent($contentId);
479
    }
480
481 View Code Duplication
    public function testLoadContentNotPublishedStatusUnauthorized()
482
    {
483
        $this->expectException(\eZ\Publish\Core\Base\Exceptions\UnauthorizedException::class);
484
485
        $permissionResolver = $this->getPermissionResolverMock();
486
        $contentService = $this->getPartlyMockedContentService(['internalLoadContent']);
487
        $content = $this->createMock(APIContent::class);
488
        $versionInfo = $this
489
            ->getMockBuilder(APIVersionInfo::class)
490
            ->getMockForAbstractClass();
491
        $content
492
            ->expects($this->once())
493
            ->method('getVersionInfo')
494
            ->will($this->returnValue($versionInfo));
495
        $contentId = 123;
496
        $contentService
497
            ->expects($this->once())
498
            ->method('internalLoadContent')
499
            ->with($contentId)
500
            ->will($this->returnValue($content));
501
502
        $permissionResolver
503
            ->expects($this->exactly(2))
504
            ->method('canUser')
505
            ->will(
506
                $this->returnValueMap(
507
                    [
508
                        ['content', 'read', $content, [], true],
509
                        ['content', 'versionread', $content, [], false],
510
                    ]
511
                )
512
            );
513
514
        $contentService->loadContent($contentId);
515
    }
516
517
    /**
518
     * @dataProvider internalLoadContentProvider
519
     */
520
    public function testInternalLoadContent($id, $languages, $versionNo, $isRemoteId, $useAlwaysAvailable)
521
    {
522
        $contentService = $this->getPartlyMockedContentService();
523
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandler */
524
        $contentHandler = $this->getPersistenceMock()->contentHandler();
525
        $realId = $id;
526
527
        if ($isRemoteId) {
528
            $realId = 123;
529
            $spiContentInfo = new SPIContentInfo(['currentVersionNo' => $versionNo ?: 7, 'id' => $realId]);
530
            $contentHandler
531
                ->expects($this->once())
532
                ->method('loadContentInfoByRemoteId')
533
                ->with($id)
534
                ->will($this->returnValue($spiContentInfo));
535
        } elseif (!empty($languages) && $useAlwaysAvailable) {
536
            $spiContentInfo = new SPIContentInfo(['alwaysAvailable' => false]);
537
            $contentHandler
538
                ->expects($this->once())
539
                ->method('loadContentInfo')
540
                ->with($id)
541
                ->will($this->returnValue($spiContentInfo));
542
        }
543
544
        $spiContent = new SPIContent([
545
            'versionInfo' => new VersionInfo([
546
                    'contentInfo' => new ContentInfo(['id' => 42, 'contentTypeId' => 123]),
547
            ]),
548
        ]);
549
        $contentHandler
550
            ->expects($this->once())
551
            ->method('load')
552
            ->with($realId, $versionNo, $languages)
553
            ->willReturn($spiContent);
554
555
        $content = $this->mockBuildContentDomainObject($spiContent, $languages);
556
557
        $this->assertSame(
558
            $content,
559
            $contentService->internalLoadContent($id, $languages, $versionNo, $isRemoteId, $useAlwaysAvailable)
560
        );
561
    }
562
563
    public function internalLoadContentProvider()
564
    {
565
        return [
566
            [123, null, null, false, false],
567
            [123, null, 456, false, false],
568
            [456, null, 123, false, true],
569
            [456, null, 2, false, false],
570
            [456, ['eng-GB'], 2, false, true],
571
            [456, ['eng-GB', 'fre-FR'], null, false, false],
572
            [456, ['eng-GB', 'fre-FR', 'nor-NO'], 2, false, false],
573
            // With remoteId
574
            [123, null, null, true, false],
575
            ['someRemoteId', null, 456, true, false],
576
            [456, null, 123, true, false],
577
            ['someRemoteId', null, 2, true, false],
578
            ['someRemoteId', ['eng-GB'], 2, true, false],
579
            [456, ['eng-GB', 'fre-FR'], null, true, false],
580
            ['someRemoteId', ['eng-GB', 'fre-FR', 'nor-NO'], 2, true, false],
581
        ];
582
    }
583
584
    public function testInternalLoadContentNotFound()
585
    {
586
        $this->expectException(\eZ\Publish\Core\Base\Exceptions\NotFoundException::class);
587
588
        $contentService = $this->getPartlyMockedContentService();
589
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandler */
590
        $contentHandler = $this->getPersistenceMock()->contentHandler();
591
        $id = 123;
592
        $versionNo = 7;
593
        $languages = null;
594
        $contentHandler
595
            ->expects($this->once())
596
            ->method('load')
597
            ->with($id, $versionNo, $languages)
598
            ->will(
599
                $this->throwException(
600
                    $this->createMock(APINotFoundException::class)
601
                )
602
            );
603
604
        $contentService->internalLoadContent($id, $languages, $versionNo);
605
    }
606
607
    /**
608
     * Test for the loadContentByContentInfo() method.
609
     *
610
     * @covers \eZ\Publish\Core\Repository\ContentService::loadContentByContentInfo
611
     */
612
    public function testLoadContentByContentInfo()
613
    {
614
        $contentServiceMock = $this->getPartlyMockedContentService(
615
            ['loadContent']
616
        );
617
        $contentServiceMock->expects(
618
            $this->once()
619
        )->method(
620
            'loadContent'
621
        )->with(
622
            $this->equalTo(42),
623
            $this->equalTo(['cro-HR']),
624
            $this->equalTo(7),
625
            $this->equalTo(false)
626
        )->will(
627
            $this->returnValue('result')
628
        );
629
630
        $result = $contentServiceMock->loadContentByContentInfo(
631
            new ContentInfo(['id' => 42]),
632
            ['cro-HR'],
633
            7
634
        );
635
636
        $this->assertEquals('result', $result);
637
    }
638
639
    /**
640
     * Test for the loadContentByVersionInfo() method.
641
     *
642
     * @covers \eZ\Publish\Core\Repository\ContentService::loadContentByVersionInfo
643
     */
644
    public function testLoadContentByVersionInfo()
645
    {
646
        $contentServiceMock = $this->getPartlyMockedContentService(
647
            ['loadContent']
648
        );
649
        $contentServiceMock->expects(
650
            $this->once()
651
        )->method(
652
            'loadContent'
653
        )->with(
654
            $this->equalTo(42),
655
            $this->equalTo(['cro-HR']),
656
            $this->equalTo(7),
657
            $this->equalTo(false)
658
        )->will(
659
            $this->returnValue('result')
660
        );
661
662
        $result = $contentServiceMock->loadContentByVersionInfo(
663
            new VersionInfo(
664
                [
665
                    'contentInfo' => new ContentInfo(['id' => 42]),
666
                    'versionNo' => 7,
667
                ]
668
            ),
669
            ['cro-HR']
670
        );
671
672
        $this->assertEquals('result', $result);
673
    }
674
675
    /**
676
     * Test for the deleteContent() method.
677
     *
678
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteContent
679
     */
680
    public function testDeleteContentThrowsUnauthorizedException()
681
    {
682
        $this->expectException(\eZ\Publish\Core\Base\Exceptions\UnauthorizedException::class);
683
684
        $permissionResolver = $this->getPermissionResolverMock();
685
        $contentService = $this->getPartlyMockedContentService(['internalLoadContentInfo']);
686
        $contentInfo = $this->createMock(APIContentInfo::class);
687
688
        $contentInfo->expects($this->any())
689
            ->method('__get')
690
            ->with('id')
691
            ->will($this->returnValue(42));
692
693
        $contentService->expects($this->once())
694
            ->method('internalLoadContentInfo')
695
            ->with(42)
696
            ->will($this->returnValue($contentInfo));
697
698
        $permissionResolver->expects($this->once())
699
            ->method('canUser')
700
            ->with('content', 'remove')
701
            ->will($this->returnValue(false));
702
703
        /* @var \eZ\Publish\API\Repository\Values\Content\ContentInfo $contentInfo */
704
        $contentService->deleteContent($contentInfo);
705
    }
706
707
    /**
708
     * Test for the deleteContent() method.
709
     *
710
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteContent
711
     */
712
    public function testDeleteContent()
713
    {
714
        $repository = $this->getRepositoryMock();
715
        $permissionResolver = $this->getPermissionResolverMock();
716
717
        $permissionResolver->expects($this->once())
718
            ->method('canUser')
719
            ->with('content', 'remove')
720
            ->will($this->returnValue(true));
721
722
        $contentService = $this->getPartlyMockedContentService(['internalLoadContentInfo']);
723
        /** @var \PHPUnit\Framework\MockObject\MockObject $urlAliasHandler */
724
        $urlAliasHandler = $this->getPersistenceMock()->urlAliasHandler();
725
        /** @var \PHPUnit\Framework\MockObject\MockObject $locationHandler */
726
        $locationHandler = $this->getPersistenceMock()->locationHandler();
727
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandler */
728
        $contentHandler = $this->getPersistenceMock()->contentHandler();
729
730
        $contentInfo = $this->createMock(APIContentInfo::class);
731
732
        $contentService->expects($this->once())
733
            ->method('internalLoadContentInfo')
734
            ->with(42)
735
            ->will($this->returnValue($contentInfo));
736
737
        $contentInfo->expects($this->any())
738
            ->method('__get')
739
            ->with('id')
740
            ->will($this->returnValue(42));
741
742
        $repository->expects($this->once())->method('beginTransaction');
743
744
        $spiLocations = [
745
            new SPILocation(['id' => 1]),
746
            new SPILocation(['id' => 2]),
747
        ];
748
        $locationHandler->expects($this->once())
749
            ->method('loadLocationsByContent')
750
            ->with(42)
751
            ->will($this->returnValue($spiLocations));
752
753
        $contentHandler->expects($this->once())
754
            ->method('deleteContent')
755
            ->with(42);
756
757
        foreach ($spiLocations as $index => $spiLocation) {
758
            $urlAliasHandler->expects($this->at($index))
759
                ->method('locationDeleted')
760
                ->with($spiLocation->id);
761
        }
762
763
        $repository->expects($this->once())->method('commit');
764
765
        /* @var \eZ\Publish\API\Repository\Values\Content\ContentInfo $contentInfo */
766
        $contentService->deleteContent($contentInfo);
767
    }
768
769
    /**
770
     * Test for the deleteContent() method.
771
     *
772
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteContent
773
     */
774
    public function testDeleteContentWithRollback()
775
    {
776
        $this->expectException(\Exception::class);
777
778
        $repository = $this->getRepositoryMock();
779
        $permissionResolver = $this->getPermissionResolverMock();
780
781
        $permissionResolver->expects($this->once())
782
            ->method('canUser')
783
            ->with('content', 'remove')
784
            ->will($this->returnValue(true));
785
786
        $contentService = $this->getPartlyMockedContentService(['internalLoadContentInfo']);
787
        /** @var \PHPUnit\Framework\MockObject\MockObject $locationHandler */
788
        $locationHandler = $this->getPersistenceMock()->locationHandler();
789
790
        $contentInfo = $this->createMock(APIContentInfo::class);
791
792
        $contentService->expects($this->once())
793
            ->method('internalLoadContentInfo')
794
            ->with(42)
795
            ->will($this->returnValue($contentInfo));
796
797
        $contentInfo->expects($this->any())
798
            ->method('__get')
799
            ->with('id')
800
            ->will($this->returnValue(42));
801
802
        $repository->expects($this->once())->method('beginTransaction');
803
804
        $locationHandler->expects($this->once())
805
            ->method('loadLocationsByContent')
806
            ->with(42)
807
            ->will($this->throwException(new \Exception()));
808
809
        $repository->expects($this->once())->method('rollback');
810
811
        /* @var \eZ\Publish\API\Repository\Values\Content\ContentInfo $contentInfo */
812
        $contentService->deleteContent($contentInfo);
813
    }
814
815
    /**
816
     * Test for the deleteVersion() method.
817
     *
818
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteVersion
819
     */
820
    public function testDeleteVersionThrowsBadStateExceptionLastVersion()
821
    {
822
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\BadStateException::class);
823
824
        $repository = $this->getRepositoryMock();
825
        $permissionResolver = $this->getPermissionResolverMock();
826
827
        $permissionResolver
828
            ->expects($this->once())
829
            ->method('canUser')
830
            ->with('content', 'versionremove')
831
            ->will($this->returnValue(true));
832
        $repository
833
            ->expects($this->never())
834
            ->method('beginTransaction');
835
836
        $contentService = $this->getPartlyMockedContentService();
837
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandler */
838
        $contentHandler = $this->getPersistenceMock()->contentHandler();
839
        $contentInfo = $this->createMock(APIContentInfo::class);
840
        $versionInfo = $this->createMock(APIVersionInfo::class);
841
842
        $contentInfo
843
            ->expects($this->any())
844
            ->method('__get')
845
            ->with('id')
846
            ->will($this->returnValue(42));
847
848
        $versionInfo
849
            ->expects($this->any())
850
            ->method('__get')
851
            ->will(
852
                $this->returnValueMap(
853
                    [
854
                        ['versionNo', 123],
855
                        ['contentInfo', $contentInfo],
856
                    ]
857
                )
858
            );
859
        $versionInfo
860
            ->expects($this->once())
861
            ->method('isPublished')
862
            ->willReturn(false);
863
864
        $contentHandler
865
            ->expects($this->once())
866
            ->method('listVersions')
867
            ->with(42)
868
            ->will($this->returnValue(['version']));
869
870
        /* @var \eZ\Publish\API\Repository\Values\Content\VersionInfo $versionInfo */
871
        $contentService->deleteVersion($versionInfo);
872
    }
873
874
    /**
875
     * Test for the createContent() method.
876
     *
877
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
878
     */
879 View Code Duplication
    public function testCreateContentThrowsInvalidArgumentExceptionMainLanguageCodeNotSet()
880
    {
881
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\InvalidArgumentException::class);
882
        $this->expectExceptionMessage('Argument \'$contentCreateStruct\' is invalid: \'mainLanguageCode\' property must be set');
883
884
        $mockedService = $this->getPartlyMockedContentService();
885
        $mockedService->createContent(new ContentCreateStruct(), []);
886
    }
887
888
    /**
889
     * Test for the createContent() method.
890
     *
891
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
892
     */
893 View Code Duplication
    public function testCreateContentThrowsInvalidArgumentExceptionContentTypeNotSet()
894
    {
895
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\InvalidArgumentException::class);
896
        $this->expectExceptionMessage('Argument \'$contentCreateStruct\' is invalid: \'contentType\' property must be set');
897
898
        $mockedService = $this->getPartlyMockedContentService();
899
        $mockedService->createContent(
900
            new ContentCreateStruct(['mainLanguageCode' => 'eng-US']),
901
            []
902
        );
903
    }
904
905
    /**
906
     * Test for the createContent() method.
907
     *
908
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
909
     */
910
    public function testCreateContentThrowsUnauthorizedException()
911
    {
912
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\UnauthorizedException::class);
913
914
        $repositoryMock = $this->getRepositoryMock();
915
916
        $permissionResolver = $this->getPermissionResolverMock();
917
        $permissionResolver->expects($this->once())
918
            ->method('getCurrentUserReference')
919
            ->will($this->returnValue(new UserReference(169)));
920
921
        $mockedService = $this->getPartlyMockedContentService();
922
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
923
        $contentType = new ContentType(
924
            [
925
                'id' => 123,
926
                'fieldDefinitions' => [],
927
            ]
928
        );
929
        $contentCreateStruct = new ContentCreateStruct(
930
            [
931
                'ownerId' => 169,
932
                'alwaysAvailable' => false,
933
                'mainLanguageCode' => 'eng-US',
934
                'contentType' => $contentType,
935
            ]
936
        );
937
938
        $contentTypeServiceMock->expects($this->once())
939
            ->method('loadContentType')
940
            ->with($this->equalTo(123))
941
            ->will($this->returnValue($contentType));
942
943
        $repositoryMock->expects($this->once())
944
            ->method('getContentTypeService')
945
            ->will($this->returnValue($contentTypeServiceMock));
946
947
        $permissionResolver->expects($this->once())
948
            ->method('canUser')
949
            ->with(
950
                $this->equalTo('content'),
951
                $this->equalTo('create'),
952
                $this->isInstanceOf(get_class($contentCreateStruct)),
953
                $this->equalTo([])
954
            )->will($this->returnValue(false));
955
956
        $mockedService->createContent(
957
            new ContentCreateStruct(
958
                [
959
                    'mainLanguageCode' => 'eng-US',
960
                    'contentType' => $contentType,
961
                ]
962
            ),
963
            []
964
        );
965
    }
966
967
    /**
968
     * Test for the createContent() method.
969
     *
970
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
971
     * @exceptionMessage Argument '$contentCreateStruct' is invalid: Another content with remoteId 'faraday' exists
972
     */
973
    public function testCreateContentThrowsInvalidArgumentExceptionDuplicateRemoteId()
974
    {
975
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\InvalidArgumentException::class);
976
977
        $repositoryMock = $this->getRepositoryMock();
978
        $permissionResolverMock = $this->getPermissionResolverMock();
979
        $permissionResolverMock
980
            ->expects($this->once())
981
            ->method('getCurrentUserReference')
982
            ->willReturn($this->createMock(UserReference::class));
983
984
        $mockedService = $this->getPartlyMockedContentService(['loadContentByRemoteId']);
985
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
986
        $contentType = new ContentType(
987
            [
988
                'id' => 123,
989
                'fieldDefinitions' => [],
990
            ]
991
        );
992
        $contentCreateStruct = new ContentCreateStruct(
993
            [
994
                'ownerId' => 169,
995
                'alwaysAvailable' => false,
996
                'remoteId' => 'faraday',
997
                'mainLanguageCode' => 'eng-US',
998
                'contentType' => $contentType,
999
            ]
1000
        );
1001
1002
        $contentTypeServiceMock->expects($this->once())
1003
            ->method('loadContentType')
1004
            ->with($this->equalTo(123))
1005
            ->will($this->returnValue($contentType));
1006
1007
        $repositoryMock->expects($this->once())
1008
            ->method('getContentTypeService')
1009
            ->will($this->returnValue($contentTypeServiceMock));
1010
1011
        $permissionResolverMock->expects($this->once())
1012
            ->method('canUser')
1013
            ->with(
1014
                $this->equalTo('content'),
1015
                $this->equalTo('create'),
1016
                $this->isInstanceOf(get_class($contentCreateStruct)),
1017
                $this->equalTo([])
1018
            )->will($this->returnValue(true));
1019
1020
        $mockedService->expects($this->once())
1021
            ->method('loadContentByRemoteId')
1022
            ->with($contentCreateStruct->remoteId)
1023
            ->will($this->returnValue('Hello...'));
1024
1025
        $mockedService->createContent(
1026
            new ContentCreateStruct(
1027
                [
1028
                    'remoteId' => 'faraday',
1029
                    'mainLanguageCode' => 'eng-US',
1030
                    'contentType' => $contentType,
1031
                ]
1032
            ),
1033
            []
1034
        );
1035
    }
1036
1037
    /**
1038
     * @param string $mainLanguageCode
1039
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $structFields
1040
     * @param \eZ\Publish\API\Repository\Values\ContentType\FieldDefinition[] $fieldDefinitions
1041
     *
1042
     * @return array
1043
     */
1044
    protected function mapStructFieldsForCreate($mainLanguageCode, $structFields, $fieldDefinitions)
1045
    {
1046
        $mappedFieldDefinitions = [];
1047
        foreach ($fieldDefinitions as $fieldDefinition) {
1048
            $mappedFieldDefinitions[$fieldDefinition->identifier] = $fieldDefinition;
1049
        }
1050
1051
        $mappedStructFields = [];
1052
        foreach ($structFields as $structField) {
1053
            if ($structField->languageCode === null) {
1054
                $languageCode = $mainLanguageCode;
1055
            } else {
1056
                $languageCode = $structField->languageCode;
1057
            }
1058
1059
            $mappedStructFields[$structField->fieldDefIdentifier][$languageCode] = (string)$structField->value;
1060
        }
1061
1062
        return $mappedStructFields;
1063
    }
1064
1065
    /**
1066
     * Returns full, possibly redundant array of field values, indexed by field definition
1067
     * identifier and language code.
1068
     *
1069
     * @throws \RuntimeException Method is intended to be used only with consistent fixtures
1070
     *
1071
     * @param string $mainLanguageCode
1072
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $structFields
1073
     * @param \eZ\Publish\API\Repository\Values\ContentType\FieldDefinition[] $fieldDefinitions
1074
     * @param array $languageCodes
1075
     *
1076
     * @return array
1077
     */
1078
    protected function determineValuesForCreate(
1079
        $mainLanguageCode,
1080
        array $structFields,
1081
        array $fieldDefinitions,
1082
        array $languageCodes
1083
    ) {
1084
        $mappedStructFields = $this->mapStructFieldsForCreate(
1085
            $mainLanguageCode,
1086
            $structFields,
1087
            $fieldDefinitions
1088
        );
1089
1090
        $values = [];
1091
1092
        foreach ($fieldDefinitions as $fieldDefinition) {
1093
            $identifier = $fieldDefinition->identifier;
1094
            foreach ($languageCodes as $languageCode) {
1095 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...
1096
                    if (isset($mappedStructFields[$identifier][$mainLanguageCode])) {
1097
                        $values[$identifier][$languageCode] = $mappedStructFields[$identifier][$mainLanguageCode];
1098
                    } else {
1099
                        $values[$identifier][$languageCode] = (string)$fieldDefinition->defaultValue;
1100
                    }
1101
                    continue;
1102
                }
1103
1104 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...
1105
                    $values[$identifier][$languageCode] = $mappedStructFields[$identifier][$languageCode];
1106
                    continue;
1107
                }
1108
1109
                $values[$identifier][$languageCode] = (string)$fieldDefinition->defaultValue;
1110
            }
1111
        }
1112
1113
        return $this->stubValues($values);
1114
    }
1115
1116
    /**
1117
     * @param string $mainLanguageCode
1118
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $structFields
1119
     *
1120
     * @return string[]
1121
     */
1122
    protected function determineLanguageCodesForCreate($mainLanguageCode, array $structFields)
1123
    {
1124
        $languageCodes = [];
1125
1126
        foreach ($structFields as $field) {
1127
            if ($field->languageCode === null || isset($languageCodes[$field->languageCode])) {
1128
                continue;
1129
            }
1130
1131
            $languageCodes[$field->languageCode] = true;
1132
        }
1133
1134
        $languageCodes[$mainLanguageCode] = true;
1135
1136
        return array_keys($languageCodes);
1137
    }
1138
1139
    /**
1140
     * Asserts that calling createContent() with given API field set causes calling
1141
     * Handler::createContent() with given SPI field set.
1142
     *
1143
     * @param string $mainLanguageCode
1144
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $structFields
1145
     * @param \eZ\Publish\SPI\Persistence\Content\Field[] $spiFields
1146
     * @param \eZ\Publish\API\Repository\Values\ContentType\FieldDefinition[] $fieldDefinitions
1147
     * @param \eZ\Publish\API\Repository\Values\Content\LocationCreateStruct[] $locationCreateStructs
1148
     * @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...
1149
     * @param bool $execute
1150
     *
1151
     * @return mixed
1152
     */
1153
    protected function assertForTestCreateContentNonRedundantFieldSet(
1154
        $mainLanguageCode,
1155
        array $structFields,
1156
        array $spiFields,
1157
        array $fieldDefinitions,
1158
        array $locationCreateStructs = [],
1159
        $withObjectStates = false,
1160
        $execute = true
1161
    ) {
1162
        $repositoryMock = $this->getRepositoryMock();
1163
        $mockedService = $this->getPartlyMockedContentService();
1164
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandlerMock */
1165
        $contentHandlerMock = $this->getPersistenceMock()->contentHandler();
1166
        /** @var \PHPUnit\Framework\MockObject\MockObject $languageHandlerMock */
1167
        $languageHandlerMock = $this->getPersistenceMock()->contentLanguageHandler();
1168
        /** @var \PHPUnit\Framework\MockObject\MockObject $objectStateHandlerMock */
1169
        $objectStateHandlerMock = $this->getPersistenceMock()->objectStateHandler();
1170
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
1171
        $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...
1172
        $domainMapperMock = $this->getDomainMapperMock();
1173
        $relationProcessorMock = $this->getRelationProcessorMock();
1174
        $nameSchemaServiceMock = $this->getNameSchemaServiceMock();
1175
        $permissionResolverMock = $this->getPermissionResolverMock();
1176
        $fieldTypeMock = $this->createMock(SPIFieldType::class);
1177
        $languageCodes = $this->determineLanguageCodesForCreate($mainLanguageCode, $structFields);
1178
        $contentType = new ContentType(
1179
            [
1180
                'id' => 123,
1181
                'fieldDefinitions' => $fieldDefinitions,
1182
                'nameSchema' => '<nameSchema>',
1183
            ]
1184
        );
1185
        $contentCreateStruct = new ContentCreateStruct(
1186
            [
1187
                'fields' => $structFields,
1188
                'mainLanguageCode' => $mainLanguageCode,
1189
                'contentType' => $contentType,
1190
                'alwaysAvailable' => false,
1191
                'ownerId' => 169,
1192
                'sectionId' => 1,
1193
            ]
1194
        );
1195
1196
        $languageHandlerMock->expects($this->any())
1197
            ->method('loadByLanguageCode')
1198
            ->with($this->isType('string'))
1199
            ->will(
1200
                $this->returnCallback(
1201
                    function () {
1202
                        return new Language(['id' => 4242]);
1203
                    }
1204
                )
1205
            );
1206
1207
        $repositoryMock->expects($this->once())->method('beginTransaction');
1208
1209
        $contentTypeServiceMock->expects($this->once())
1210
            ->method('loadContentType')
1211
            ->with($this->equalTo($contentType->id))
1212
            ->will($this->returnValue($contentType));
1213
1214
        $repositoryMock->expects($this->once())
1215
            ->method('getContentTypeService')
1216
            ->will($this->returnValue($contentTypeServiceMock));
1217
1218
        $that = $this;
1219
        $permissionResolverMock->expects($this->once())
1220
            ->method('canUser')
1221
            ->with(
1222
                $this->equalTo('content'),
1223
                $this->equalTo('create'),
1224
                $this->isInstanceOf(APIContentCreateStruct::class),
1225
                $this->equalTo($locationCreateStructs)
1226
            )->will(
1227
                $this->returnCallback(
1228
                    function () use ($that, $contentCreateStruct) {
1229
                        $that->assertEquals($contentCreateStruct, func_get_arg(2));
1230
1231
                        return true;
1232
                    }
1233
                )
1234
            );
1235
1236
        $domainMapperMock->expects($this->once())
1237
            ->method('getUniqueHash')
1238
            ->with($this->isInstanceOf(APIContentCreateStruct::class))
1239
            ->will(
1240
                $this->returnCallback(
1241
                    function ($object) use ($that, $contentCreateStruct) {
1242
                        $that->assertEquals($contentCreateStruct, $object);
1243
1244
                        return 'hash';
1245
                    }
1246
                )
1247
            );
1248
1249
        $fieldTypeMock->expects($this->any())
1250
            ->method('acceptValue')
1251
            ->will(
1252
                $this->returnCallback(
1253
                    function ($valueString) {
1254
                        return new ValueStub($valueString);
1255
                    }
1256
                )
1257
            );
1258
1259
        $fieldTypeMock->expects($this->any())
1260
            ->method('toPersistenceValue')
1261
            ->will(
1262
                $this->returnCallback(
1263
                    function (ValueStub $value) {
1264
                        return (string)$value;
1265
                    }
1266
                )
1267
            );
1268
1269
        $emptyValue = self::EMPTY_FIELD_VALUE;
1270
        $fieldTypeMock->expects($this->any())
1271
            ->method('isEmptyValue')
1272
            ->will(
1273
                $this->returnCallback(
1274
                    function (ValueStub $value) use ($emptyValue) {
1275
                        return $emptyValue === (string)$value;
1276
                    }
1277
                )
1278
            );
1279
1280
        $fieldTypeMock->expects($this->any())
1281
            ->method('validate')
1282
            ->will($this->returnValue([]));
1283
1284
        $this->getFieldTypeRegistryMock()->expects($this->any())
1285
            ->method('getFieldType')
1286
            ->will($this->returnValue($fieldTypeMock));
1287
1288
        $relationProcessorMock
1289
            ->expects($this->exactly(count($fieldDefinitions) * count($languageCodes)))
1290
            ->method('appendFieldRelations')
1291
            ->with(
1292
                $this->isType('array'),
1293
                $this->isType('array'),
1294
                $this->isInstanceOf(SPIFieldType::class),
1295
                $this->isInstanceOf(Value::class),
1296
                $this->anything()
1297
            );
1298
1299
        $values = $this->determineValuesForCreate(
1300
            $mainLanguageCode,
1301
            $structFields,
1302
            $fieldDefinitions,
1303
            $languageCodes
1304
        );
1305
        $nameSchemaServiceMock->expects($this->once())
1306
            ->method('resolve')
1307
            ->with(
1308
                $this->equalTo($contentType->nameSchema),
1309
                $this->equalTo($contentType),
1310
                $this->equalTo($values),
1311
                $this->equalTo($languageCodes)
1312
            )->will($this->returnValue([]));
1313
1314
        $relationProcessorMock->expects($this->any())
1315
            ->method('processFieldRelations')
1316
            ->with(
1317
                $this->isType('array'),
1318
                $this->equalTo(42),
1319
                $this->isType('int'),
1320
                $this->equalTo($contentType),
1321
                $this->equalTo([])
1322
            );
1323
1324
        if (!$withObjectStates) {
1325
            $objectStateHandlerMock->expects($this->once())
1326
                ->method('loadAllGroups')
1327
                ->will($this->returnValue([]));
1328
        }
1329
1330
        if ($execute) {
1331
            $spiContentCreateStruct = new SPIContentCreateStruct(
1332
                [
1333
                    'name' => [],
1334
                    'typeId' => 123,
1335
                    'sectionId' => 1,
1336
                    'ownerId' => 169,
1337
                    'remoteId' => 'hash',
1338
                    'fields' => $spiFields,
1339
                    'modified' => time(),
1340
                    'initialLanguageId' => 4242,
1341
                ]
1342
            );
1343
            $spiContentCreateStruct2 = clone $spiContentCreateStruct;
1344
            ++$spiContentCreateStruct2->modified;
1345
1346
            $spiContent = new SPIContent(
1347
                [
1348
                    'versionInfo' => new SPIContent\VersionInfo(
1349
                        [
1350
                            'contentInfo' => new SPIContent\ContentInfo(['id' => 42]),
1351
                            'versionNo' => 7,
1352
                        ]
1353
                    ),
1354
                ]
1355
            );
1356
1357
            $contentHandlerMock->expects($this->once())
1358
                ->method('create')
1359
                ->with($this->logicalOr($spiContentCreateStruct, $spiContentCreateStruct2))
1360
                ->will($this->returnValue($spiContent));
1361
1362
            $repositoryMock->expects($this->once())->method('commit');
1363
            $domainMapperMock->expects($this->once())
1364
                ->method('buildContentDomainObject')
1365
                ->with(
1366
                    $this->isInstanceOf(SPIContent::class),
1367
                    $this->equalTo($contentType)
1368
                );
1369
1370
            $mockedService->createContent($contentCreateStruct, []);
1371
        }
1372
1373
        return $contentCreateStruct;
1374
    }
1375
1376
    public function providerForTestCreateContentNonRedundantFieldSet1()
1377
    {
1378
        $spiFields = [
1379
            new SPIField(
1380
                [
1381
                    'fieldDefinitionId' => 'fieldDefinitionId',
1382
                    'type' => 'fieldTypeIdentifier',
1383
                    'value' => 'newValue',
1384
                    'languageCode' => 'eng-US',
1385
                ]
1386
            ),
1387
        ];
1388
1389
        return [
1390
            // 0. Without language set
1391
            [
1392
                'eng-US',
1393
                [
1394
                    new Field(
1395
                        [
1396
                            'fieldDefIdentifier' => 'identifier',
1397
                            'value' => 'newValue',
1398
                            'languageCode' => 'eng-US',
1399
                        ]
1400
                    ),
1401
                ],
1402
                $spiFields,
1403
            ],
1404
            // 1. Without language set
1405
            [
1406
                'eng-US',
1407
                [
1408
                    new Field(
1409
                        [
1410
                            'fieldDefIdentifier' => 'identifier',
1411
                            'value' => 'newValue',
1412
                            'languageCode' => null,
1413
                        ]
1414
                    ),
1415
                ],
1416
                $spiFields,
1417
            ],
1418
        ];
1419
    }
1420
1421
    /**
1422
     * Test for the createContent() method.
1423
     *
1424
     * Testing the simplest use case.
1425
     *
1426
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
1427
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForCreate
1428
     * @covers \eZ\Publish\Core\Repository\ContentService::cloneField
1429
     * @covers \eZ\Publish\Core\Repository\ContentService::getDefaultObjectStates
1430
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
1431
     * @dataProvider providerForTestCreateContentNonRedundantFieldSet1
1432
     */
1433
    public function testCreateContentNonRedundantFieldSet1($mainLanguageCode, $structFields, $spiFields)
1434
    {
1435
        $fieldDefinitions = [
1436
            new FieldDefinition(
1437
                [
1438
                    'id' => 'fieldDefinitionId',
1439
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
1440
                    'isTranslatable' => false,
1441
                    'identifier' => 'identifier',
1442
                    'isRequired' => false,
1443
                    'defaultValue' => 'defaultValue',
1444
                ]
1445
            ),
1446
        ];
1447
1448
        $this->assertForTestCreateContentNonRedundantFieldSet(
1449
            $mainLanguageCode,
1450
            $structFields,
1451
            $spiFields,
1452
            $fieldDefinitions
1453
        );
1454
    }
1455
1456
    public function providerForTestCreateContentNonRedundantFieldSet2()
1457
    {
1458
        $spiFields = [
1459
            new SPIField(
1460
                [
1461
                    'fieldDefinitionId' => 'fieldDefinitionId1',
1462
                    'type' => 'fieldTypeIdentifier',
1463
                    'value' => 'newValue1',
1464
                    'languageCode' => 'eng-US',
1465
                ]
1466
            ),
1467
            new SPIField(
1468
                [
1469
                    'fieldDefinitionId' => 'fieldDefinitionId2',
1470
                    'type' => 'fieldTypeIdentifier',
1471
                    'value' => 'newValue2',
1472
                    'languageCode' => 'ger-DE',
1473
                ]
1474
            ),
1475
        ];
1476
1477
        return [
1478
            // 0. With language set
1479
            [
1480
                'eng-US',
1481
                [
1482
                    new Field(
1483
                        [
1484
                            'fieldDefIdentifier' => 'identifier1',
1485
                            'value' => 'newValue1',
1486
                            'languageCode' => 'eng-US',
1487
                        ]
1488
                    ),
1489
                    new Field(
1490
                        [
1491
                            'fieldDefIdentifier' => 'identifier2',
1492
                            'value' => 'newValue2',
1493
                            'languageCode' => 'ger-DE',
1494
                        ]
1495
                    ),
1496
                ],
1497
                $spiFields,
1498
            ],
1499
            // 1. Without language set
1500
            [
1501
                'eng-US',
1502
                [
1503
                    new Field(
1504
                        [
1505
                            'fieldDefIdentifier' => 'identifier1',
1506
                            'value' => 'newValue1',
1507
                            'languageCode' => null,
1508
                        ]
1509
                    ),
1510
                    new Field(
1511
                        [
1512
                            'fieldDefIdentifier' => 'identifier2',
1513
                            'value' => 'newValue2',
1514
                            'languageCode' => 'ger-DE',
1515
                        ]
1516
                    ),
1517
                ],
1518
                $spiFields,
1519
            ],
1520
        ];
1521
    }
1522
1523
    /**
1524
     * Test for the createContent() method.
1525
     *
1526
     * Testing multiple languages with multiple translatable fields with empty default value.
1527
     *
1528
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
1529
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForCreate
1530
     * @covers \eZ\Publish\Core\Repository\ContentService::cloneField
1531
     * @covers \eZ\Publish\Core\Repository\ContentService::getDefaultObjectStates
1532
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
1533
     * @dataProvider providerForTestCreateContentNonRedundantFieldSet2
1534
     */
1535
    public function testCreateContentNonRedundantFieldSet2($mainLanguageCode, $structFields, $spiFields)
1536
    {
1537
        $fieldDefinitions = [
1538
            new FieldDefinition(
1539
                [
1540
                    'id' => 'fieldDefinitionId1',
1541
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
1542
                    'isTranslatable' => true,
1543
                    'identifier' => 'identifier1',
1544
                    'isRequired' => false,
1545
                    'defaultValue' => self::EMPTY_FIELD_VALUE,
1546
                ]
1547
            ),
1548
            new FieldDefinition(
1549
                [
1550
                    'id' => 'fieldDefinitionId2',
1551
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
1552
                    'isTranslatable' => true,
1553
                    'identifier' => 'identifier2',
1554
                    'isRequired' => false,
1555
                    'defaultValue' => self::EMPTY_FIELD_VALUE,
1556
                ]
1557
            ),
1558
        ];
1559
1560
        $this->assertForTestCreateContentNonRedundantFieldSet(
1561
            $mainLanguageCode,
1562
            $structFields,
1563
            $spiFields,
1564
            $fieldDefinitions
1565
        );
1566
    }
1567
1568
    public function providerForTestCreateContentNonRedundantFieldSetComplex()
1569
    {
1570
        $spiFields0 = [
1571
            new SPIField(
1572
                [
1573
                    'fieldDefinitionId' => 'fieldDefinitionId2',
1574
                    'type' => 'fieldTypeIdentifier',
1575
                    'value' => 'defaultValue2',
1576
                    'languageCode' => 'eng-US',
1577
                ]
1578
            ),
1579
            new SPIField(
1580
                [
1581
                    'fieldDefinitionId' => 'fieldDefinitionId4',
1582
                    'type' => 'fieldTypeIdentifier',
1583
                    'value' => 'defaultValue4',
1584
                    'languageCode' => 'eng-US',
1585
                ]
1586
            ),
1587
        ];
1588
        $spiFields1 = [
1589
            new SPIField(
1590
                [
1591
                    'fieldDefinitionId' => 'fieldDefinitionId1',
1592
                    'type' => 'fieldTypeIdentifier',
1593
                    'value' => 'newValue1',
1594
                    'languageCode' => 'ger-DE',
1595
                ]
1596
            ),
1597
            new SPIField(
1598
                [
1599
                    'fieldDefinitionId' => 'fieldDefinitionId2',
1600
                    'type' => 'fieldTypeIdentifier',
1601
                    'value' => 'defaultValue2',
1602
                    'languageCode' => 'ger-DE',
1603
                ]
1604
            ),
1605
            new SPIField(
1606
                [
1607
                    'fieldDefinitionId' => 'fieldDefinitionId2',
1608
                    'type' => 'fieldTypeIdentifier',
1609
                    'value' => 'newValue2',
1610
                    'languageCode' => 'eng-US',
1611
                ]
1612
            ),
1613
            new SPIField(
1614
                [
1615
                    'fieldDefinitionId' => 'fieldDefinitionId4',
1616
                    'type' => 'fieldTypeIdentifier',
1617
                    'value' => 'newValue4',
1618
                    'languageCode' => 'eng-US',
1619
                ]
1620
            ),
1621
        ];
1622
1623
        return [
1624
            // 0. Creating by default values only
1625
            [
1626
                'eng-US',
1627
                [],
1628
                $spiFields0,
1629
            ],
1630
            // 1. Multiple languages with language set
1631
            [
1632
                'eng-US',
1633
                [
1634
                    new Field(
1635
                        [
1636
                            'fieldDefIdentifier' => 'identifier1',
1637
                            'value' => 'newValue1',
1638
                            'languageCode' => 'ger-DE',
1639
                        ]
1640
                    ),
1641
                    new Field(
1642
                        [
1643
                            'fieldDefIdentifier' => 'identifier2',
1644
                            'value' => 'newValue2',
1645
                            'languageCode' => 'eng-US',
1646
                        ]
1647
                    ),
1648
                    new Field(
1649
                        [
1650
                            'fieldDefIdentifier' => 'identifier4',
1651
                            'value' => 'newValue4',
1652
                            'languageCode' => 'eng-US',
1653
                        ]
1654
                    ),
1655
                ],
1656
                $spiFields1,
1657
            ],
1658
            // 2. Multiple languages without language set
1659
            [
1660
                'eng-US',
1661
                [
1662
                    new Field(
1663
                        [
1664
                            'fieldDefIdentifier' => 'identifier1',
1665
                            'value' => 'newValue1',
1666
                            'languageCode' => 'ger-DE',
1667
                        ]
1668
                    ),
1669
                    new Field(
1670
                        [
1671
                            'fieldDefIdentifier' => 'identifier2',
1672
                            'value' => 'newValue2',
1673
                            'languageCode' => null,
1674
                        ]
1675
                    ),
1676
                    new Field(
1677
                        [
1678
                            'fieldDefIdentifier' => 'identifier4',
1679
                            'value' => 'newValue4',
1680
                            'languageCode' => null,
1681
                        ]
1682
                    ),
1683
                ],
1684
                $spiFields1,
1685
            ],
1686
        ];
1687
    }
1688
1689
    protected function fixturesForTestCreateContentNonRedundantFieldSetComplex()
1690
    {
1691
        return [
1692
            new FieldDefinition(
1693
                [
1694
                    'id' => 'fieldDefinitionId1',
1695
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
1696
                    'isTranslatable' => true,
1697
                    'identifier' => 'identifier1',
1698
                    'isRequired' => false,
1699
                    'defaultValue' => self::EMPTY_FIELD_VALUE,
1700
                ]
1701
            ),
1702
            new FieldDefinition(
1703
                [
1704
                    'id' => 'fieldDefinitionId2',
1705
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
1706
                    'isTranslatable' => true,
1707
                    'identifier' => 'identifier2',
1708
                    'isRequired' => false,
1709
                    'defaultValue' => 'defaultValue2',
1710
                ]
1711
            ),
1712
            new FieldDefinition(
1713
                [
1714
                    'id' => 'fieldDefinitionId3',
1715
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
1716
                    'isTranslatable' => false,
1717
                    'identifier' => 'identifier3',
1718
                    'isRequired' => false,
1719
                    'defaultValue' => self::EMPTY_FIELD_VALUE,
1720
                ]
1721
            ),
1722
            new FieldDefinition(
1723
                [
1724
                    'id' => 'fieldDefinitionId4',
1725
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
1726
                    'isTranslatable' => false,
1727
                    'identifier' => 'identifier4',
1728
                    'isRequired' => false,
1729
                    'defaultValue' => 'defaultValue4',
1730
                ]
1731
            ),
1732
        ];
1733
    }
1734
1735
    /**
1736
     * Test for the createContent() method.
1737
     *
1738
     * Testing multiple languages with multiple translatable fields with empty default value.
1739
     *
1740
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
1741
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForCreate
1742
     * @covers \eZ\Publish\Core\Repository\ContentService::cloneField
1743
     * @covers \eZ\Publish\Core\Repository\ContentService::getDefaultObjectStates
1744
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
1745
     * @dataProvider providerForTestCreateContentNonRedundantFieldSetComplex
1746
     */
1747
    public function testCreateContentNonRedundantFieldSetComplex($mainLanguageCode, $structFields, $spiFields)
1748
    {
1749
        $fieldDefinitions = $this->fixturesForTestCreateContentNonRedundantFieldSetComplex();
1750
1751
        $this->assertForTestCreateContentNonRedundantFieldSet(
1752
            $mainLanguageCode,
1753
            $structFields,
1754
            $spiFields,
1755
            $fieldDefinitions
1756
        );
1757
    }
1758
1759 View Code Duplication
    public function providerForTestCreateContentWithInvalidLanguage()
1760
    {
1761
        return [
1762
            [
1763
                'eng-GB',
1764
                [
1765
                    new Field(
1766
                        [
1767
                            'fieldDefIdentifier' => 'identifier',
1768
                            'value' => 'newValue',
1769
                            'languageCode' => 'Klingon',
1770
                        ]
1771
                    ),
1772
                ],
1773
            ],
1774
            [
1775
                'Klingon',
1776
                [
1777
                    new Field(
1778
                        [
1779
                            'fieldDefIdentifier' => 'identifier',
1780
                            'value' => 'newValue',
1781
                            'languageCode' => 'eng-GB',
1782
                        ]
1783
                    ),
1784
                ],
1785
            ],
1786
        ];
1787
    }
1788
1789
    /**
1790
     * Test for the updateContent() method.
1791
     *
1792
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
1793
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
1794
     * @dataProvider providerForTestCreateContentWithInvalidLanguage
1795
     */
1796
    public function testCreateContentWithInvalidLanguage($mainLanguageCode, $structFields)
1797
    {
1798
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\NotFoundException::class);
1799
        $this->expectExceptionMessage('Could not find \'Language\' with identifier \'Klingon\'');
1800
1801
        $repositoryMock = $this->getRepositoryMock();
1802
        $mockedService = $this->getPartlyMockedContentService();
1803
        /** @var \PHPUnit\Framework\MockObject\MockObject $languageHandlerMock */
1804
        $languageHandlerMock = $this->getPersistenceMock()->contentLanguageHandler();
1805
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
1806
        $domainMapperMock = $this->getDomainMapperMock();
1807
        $permissionResolver = $this->getPermissionResolverMock();
1808
1809
        $contentType = new ContentType(
1810
            [
1811
                'id' => 123,
1812
                'fieldDefinitions' => [],
1813
            ]
1814
        );
1815
        $contentCreateStruct = new ContentCreateStruct(
1816
            [
1817
                'fields' => $structFields,
1818
                'mainLanguageCode' => $mainLanguageCode,
1819
                'contentType' => $contentType,
1820
                'alwaysAvailable' => false,
1821
                'ownerId' => 169,
1822
                'sectionId' => 1,
1823
            ]
1824
        );
1825
1826
        $languageHandlerMock->expects($this->any())
1827
            ->method('loadByLanguageCode')
1828
            ->with($this->isType('string'))
1829
            ->will(
1830
                $this->returnCallback(
1831 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...
1832
                        if ($languageCode === 'Klingon') {
1833
                            throw new NotFoundException('Language', 'Klingon');
1834
                        }
1835
1836
                        return new Language(['id' => 4242]);
1837
                    }
1838
                )
1839
            );
1840
1841
        $contentTypeServiceMock->expects($this->once())
1842
            ->method('loadContentType')
1843
            ->with($this->equalTo($contentType->id))
1844
            ->will($this->returnValue($contentType));
1845
1846
        $repositoryMock->expects($this->once())
1847
            ->method('getContentTypeService')
1848
            ->will($this->returnValue($contentTypeServiceMock));
1849
1850
        $that = $this;
1851
        $permissionResolver->expects($this->once())
1852
            ->method('canUser')
1853
            ->with(
1854
                $this->equalTo('content'),
1855
                $this->equalTo('create'),
1856
                $this->isInstanceOf(APIContentCreateStruct::class),
1857
                $this->equalTo([])
1858
            )->will(
1859
                $this->returnCallback(
1860
                    function () use ($that, $contentCreateStruct) {
1861
                        $that->assertEquals($contentCreateStruct, func_get_arg(2));
1862
1863
                        return true;
1864
                    }
1865
                )
1866
            );
1867
1868
        $domainMapperMock->expects($this->once())
1869
            ->method('getUniqueHash')
1870
            ->with($this->isInstanceOf(APIContentCreateStruct::class))
1871
            ->will(
1872
                $this->returnCallback(
1873
                    function ($object) use ($that, $contentCreateStruct) {
1874
                        $that->assertEquals($contentCreateStruct, $object);
1875
1876
                        return 'hash';
1877
                    }
1878
                )
1879
            );
1880
1881
        $mockedService->createContent($contentCreateStruct, []);
1882
    }
1883
1884
    protected function assertForCreateContentContentValidationException(
1885
        $mainLanguageCode,
1886
        $structFields,
1887
        $fieldDefinitions = []
1888
    ) {
1889
        $repositoryMock = $this->getRepositoryMock();
1890
        $mockedService = $this->getPartlyMockedContentService(['loadContentByRemoteId']);
1891
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
1892
        $permissionResolver = $this->getPermissionResolverMock();
1893
1894
        $contentType = new ContentType(
1895
            [
1896
                'id' => 123,
1897
                'fieldDefinitions' => $fieldDefinitions,
1898
            ]
1899
        );
1900
        $contentCreateStruct = new ContentCreateStruct(
1901
            [
1902
                'ownerId' => 169,
1903
                'alwaysAvailable' => false,
1904
                'remoteId' => 'faraday',
1905
                'mainLanguageCode' => $mainLanguageCode,
1906
                'fields' => $structFields,
1907
                'contentType' => $contentType,
1908
            ]
1909
        );
1910
1911
        $contentTypeServiceMock->expects($this->once())
1912
            ->method('loadContentType')
1913
            ->with($this->equalTo(123))
1914
            ->will($this->returnValue($contentType));
1915
1916
        $repositoryMock->expects($this->once())
1917
            ->method('getContentTypeService')
1918
            ->will($this->returnValue($contentTypeServiceMock));
1919
1920
        $permissionResolver->expects($this->once())
1921
            ->method('canUser')
1922
            ->with(
1923
                $this->equalTo('content'),
1924
                $this->equalTo('create'),
1925
                $this->isInstanceOf(get_class($contentCreateStruct)),
1926
                $this->equalTo([])
1927
            )->will($this->returnValue(true));
1928
1929
        $mockedService->expects($this->once())
1930
            ->method('loadContentByRemoteId')
1931
            ->with($contentCreateStruct->remoteId)
1932
            ->will(
1933
                $this->throwException(new NotFoundException('Content', 'faraday'))
1934
            );
1935
1936
        $mockedService->createContent($contentCreateStruct, []);
1937
    }
1938
1939 View Code Duplication
    public function providerForTestCreateContentThrowsContentValidationExceptionFieldDefinition()
1940
    {
1941
        return [
1942
            [
1943
                'eng-GB',
1944
                [
1945
                    new Field(
1946
                        [
1947
                            'fieldDefIdentifier' => 'identifier',
1948
                            'value' => 'newValue',
1949
                            'languageCode' => 'eng-GB',
1950
                        ]
1951
                    ),
1952
                ],
1953
            ],
1954
        ];
1955
    }
1956
1957
    /**
1958
     * Test for the createContent() method.
1959
     *
1960
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
1961
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForCreate
1962
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
1963
     * @dataProvider providerForTestCreateContentThrowsContentValidationExceptionFieldDefinition
1964
     */
1965
    public function testCreateContentThrowsContentValidationExceptionFieldDefinition($mainLanguageCode, $structFields)
1966
    {
1967
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\ContentValidationException::class);
1968
        $this->expectExceptionMessage('Field definition \'identifier\' does not exist in given ContentType');
1969
1970
        $this->assertForCreateContentContentValidationException(
1971
            $mainLanguageCode,
1972
            $structFields,
1973
            []
1974
        );
1975
    }
1976
1977 View Code Duplication
    public function providerForTestCreateContentThrowsContentValidationExceptionTranslation()
1978
    {
1979
        return [
1980
            [
1981
                'eng-GB',
1982
                [
1983
                    new Field(
1984
                        [
1985
                            'fieldDefIdentifier' => 'identifier',
1986
                            'value' => 'newValue',
1987
                            'languageCode' => 'eng-US',
1988
                        ]
1989
                    ),
1990
                ],
1991
            ],
1992
        ];
1993
    }
1994
1995
    /**
1996
     * Test for the createContent() method.
1997
     *
1998
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
1999
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForCreate
2000
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
2001
     * @dataProvider providerForTestCreateContentThrowsContentValidationExceptionTranslation
2002
     */
2003 View Code Duplication
    public function testCreateContentThrowsContentValidationExceptionTranslation($mainLanguageCode, $structFields)
2004
    {
2005
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\ContentValidationException::class);
2006
        $this->expectExceptionMessage('A value is set for non translatable field definition \'identifier\' with language \'eng-US\'');
2007
2008
        $fieldDefinitions = [
2009
            new FieldDefinition(
2010
                [
2011
                    'id' => 'fieldDefinitionId1',
2012
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
2013
                    'isTranslatable' => false,
2014
                    'identifier' => 'identifier',
2015
                    'isRequired' => false,
2016
                    'defaultValue' => self::EMPTY_FIELD_VALUE,
2017
                ]
2018
            ),
2019
        ];
2020
2021
        $this->assertForCreateContentContentValidationException(
2022
            $mainLanguageCode,
2023
            $structFields,
2024
            $fieldDefinitions
2025
        );
2026
    }
2027
2028
    /**
2029
     * Asserts behaviour necessary for testing ContentFieldValidationException because of required
2030
     * field being empty.
2031
     *
2032
     * @param string $mainLanguageCode
2033
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $structFields
2034
     * @param \eZ\Publish\API\Repository\Values\ContentType\FieldDefinition[] $fieldDefinitions
2035
     *
2036
     * @return mixed
2037
     */
2038
    protected function assertForTestCreateContentRequiredField(
2039
        $mainLanguageCode,
2040
        array $structFields,
2041
        array $fieldDefinitions
2042
    ) {
2043
        $repositoryMock = $this->getRepositoryMock();
2044
        /** @var \PHPUnit\Framework\MockObject\MockObject $languageHandlerMock */
2045
        $languageHandlerMock = $this->getPersistenceMock()->contentLanguageHandler();
2046
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
2047
        $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...
2048
        $domainMapperMock = $this->getDomainMapperMock();
2049
        $fieldTypeMock = $this->createMock(SPIFieldType::class);
2050
        $permissionResolver = $this->getPermissionResolverMock();
2051
2052
        $contentType = new ContentType(
2053
            [
2054
                'id' => 123,
2055
                'fieldDefinitions' => $fieldDefinitions,
2056
                'nameSchema' => '<nameSchema>',
2057
            ]
2058
        );
2059
        $contentCreateStruct = new ContentCreateStruct(
2060
            [
2061
                'fields' => $structFields,
2062
                'mainLanguageCode' => $mainLanguageCode,
2063
                'contentType' => $contentType,
2064
                'alwaysAvailable' => false,
2065
                'ownerId' => 169,
2066
                'sectionId' => 1,
2067
            ]
2068
        );
2069
2070
        $languageHandlerMock->expects($this->any())
2071
            ->method('loadByLanguageCode')
2072
            ->with($this->isType('string'))
2073
            ->will(
2074
                $this->returnCallback(
2075
                    function () {
2076
                        return new Language(['id' => 4242]);
2077
                    }
2078
                )
2079
            );
2080
2081
        $contentTypeServiceMock->expects($this->once())
2082
            ->method('loadContentType')
2083
            ->with($this->equalTo($contentType->id))
2084
            ->will($this->returnValue($contentType));
2085
2086
        $repositoryMock->expects($this->once())
2087
            ->method('getContentTypeService')
2088
            ->will($this->returnValue($contentTypeServiceMock));
2089
2090
        $that = $this;
2091
        $permissionResolver->expects($this->once())
2092
            ->method('canUser')
2093
            ->with(
2094
                $this->equalTo('content'),
2095
                $this->equalTo('create'),
2096
                $this->isInstanceOf(APIContentCreateStruct::class),
2097
                $this->equalTo([])
2098
            )->will(
2099
                $this->returnCallback(
2100
                    function () use ($that, $contentCreateStruct) {
2101
                        $that->assertEquals($contentCreateStruct, func_get_arg(2));
2102
2103
                        return true;
2104
                    }
2105
                )
2106
            );
2107
2108
        $domainMapperMock->expects($this->once())
2109
            ->method('getUniqueHash')
2110
            ->with($this->isInstanceOf(APIContentCreateStruct::class))
2111
            ->will(
2112
                $this->returnCallback(
2113
                    function ($object) use ($that, $contentCreateStruct) {
2114
                        $that->assertEquals($contentCreateStruct, $object);
2115
2116
                        return 'hash';
2117
                    }
2118
                )
2119
            );
2120
2121
        $fieldTypeMock->expects($this->any())
2122
            ->method('acceptValue')
2123
            ->will(
2124
                $this->returnCallback(
2125
                    function ($valueString) {
2126
                        return new ValueStub($valueString);
2127
                    }
2128
                )
2129
            );
2130
2131
        $emptyValue = self::EMPTY_FIELD_VALUE;
2132
        $fieldTypeMock->expects($this->any())
2133
            ->method('isEmptyValue')
2134
            ->will(
2135
                $this->returnCallback(
2136
                    function (ValueStub $value) use ($emptyValue) {
2137
                        return $emptyValue === (string)$value;
2138
                    }
2139
                )
2140
            );
2141
2142
        $fieldTypeMock->expects($this->any())
2143
            ->method('validate')
2144
            ->will($this->returnValue([]));
2145
2146
        $this->getFieldTypeRegistryMock()->expects($this->any())
2147
            ->method('getFieldType')
2148
            ->will($this->returnValue($fieldTypeMock));
2149
2150
        return $contentCreateStruct;
2151
    }
2152
2153 View Code Duplication
    public function providerForTestCreateContentThrowsContentValidationExceptionRequiredField()
2154
    {
2155
        return [
2156
            [
2157
                'eng-US',
2158
                [
2159
                    new Field(
2160
                        [
2161
                            'fieldDefIdentifier' => 'identifier',
2162
                            'value' => self::EMPTY_FIELD_VALUE,
2163
                            'languageCode' => null,
2164
                        ]
2165
                    ),
2166
                ],
2167
                'identifier',
2168
                'eng-US',
2169
            ],
2170
        ];
2171
    }
2172
2173
    /**
2174
     * Test for the createContent() method.
2175
     *
2176
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
2177
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForCreate
2178
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
2179
     * @dataProvider providerForTestCreateContentThrowsContentValidationExceptionRequiredField
2180
     */
2181
    public function testCreateContentRequiredField(
2182
        $mainLanguageCode,
2183
        $structFields,
2184
        $identifier,
2185
        $languageCode
2186
    ) {
2187
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\ContentFieldValidationException::class);
2188
2189
        $fieldDefinitions = [
2190
            new FieldDefinition(
2191
                [
2192
                    'id' => 'fieldDefinitionId',
2193
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
2194
                    'isTranslatable' => true,
2195
                    'identifier' => 'identifier',
2196
                    'isRequired' => true,
2197
                    'defaultValue' => 'defaultValue',
2198
                ]
2199
            ),
2200
        ];
2201
        $contentCreateStruct = $this->assertForTestCreateContentRequiredField(
2202
            $mainLanguageCode,
2203
            $structFields,
2204
            $fieldDefinitions
2205
        );
2206
2207
        $mockedService = $this->getPartlyMockedContentService();
2208
2209
        try {
2210
            $mockedService->createContent($contentCreateStruct, []);
2211
        } catch (ContentValidationException $e) {
2212
            $this->assertEquals(
2213
                "Value for required field definition '{$identifier}' with language '{$languageCode}' is empty",
2214
                $e->getMessage()
2215
            );
2216
2217
            throw $e;
2218
        }
2219
    }
2220
2221
    /**
2222
     * Asserts behaviour necessary for testing ContentFieldValidationException because of
2223
     * field not being valid.
2224
     *
2225
     * @param string $mainLanguageCode
2226
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $structFields
2227
     * @param \eZ\Publish\API\Repository\Values\ContentType\FieldDefinition[] $fieldDefinitions
2228
     *
2229
     * @return mixed
2230
     */
2231
    protected function assertForTestCreateContentThrowsContentFieldValidationException(
2232
        $mainLanguageCode,
2233
        array $structFields,
2234
        array $fieldDefinitions
2235
    ) {
2236
        $repositoryMock = $this->getRepositoryMock();
2237
        /** @var \PHPUnit\Framework\MockObject\MockObject $languageHandlerMock */
2238
        $languageHandlerMock = $this->getPersistenceMock()->contentLanguageHandler();
2239
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
2240
        $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...
2241
        $domainMapperMock = $this->getDomainMapperMock();
2242
        $relationProcessorMock = $this->getRelationProcessorMock();
2243
        $fieldTypeMock = $this->createMock(SPIFieldType::class);
2244
        $languageCodes = $this->determineLanguageCodesForCreate($mainLanguageCode, $structFields);
2245
        $permissionResolver = $this->getPermissionResolverMock();
2246
2247
        $contentType = new ContentType(
2248
            [
2249
                'id' => 123,
2250
                'fieldDefinitions' => $fieldDefinitions,
2251
                'nameSchema' => '<nameSchema>',
2252
            ]
2253
        );
2254
        $contentCreateStruct = new ContentCreateStruct(
2255
            [
2256
                'fields' => $structFields,
2257
                'mainLanguageCode' => $mainLanguageCode,
2258
                'contentType' => $contentType,
2259
                'alwaysAvailable' => false,
2260
                'ownerId' => 169,
2261
                'sectionId' => 1,
2262
            ]
2263
        );
2264
2265
        $languageHandlerMock->expects($this->any())
2266
            ->method('loadByLanguageCode')
2267
            ->with($this->isType('string'))
2268
            ->will(
2269
                $this->returnCallback(
2270
                    function () {
2271
                        return new Language(['id' => 4242]);
2272
                    }
2273
                )
2274
            );
2275
2276
        $contentTypeServiceMock->expects($this->once())
2277
            ->method('loadContentType')
2278
            ->with($this->equalTo($contentType->id))
2279
            ->will($this->returnValue($contentType));
2280
2281
        $repositoryMock->expects($this->once())
2282
            ->method('getContentTypeService')
2283
            ->will($this->returnValue($contentTypeServiceMock));
2284
2285
        $that = $this;
2286
        $permissionResolver->expects($this->once())
2287
            ->method('canUser')
2288
            ->with(
2289
                $this->equalTo('content'),
2290
                $this->equalTo('create'),
2291
                $this->isInstanceOf(APIContentCreateStruct::class),
2292
                $this->equalTo([])
2293
            )->will(
2294
                $this->returnCallback(
2295
                    function () use ($that, $contentCreateStruct) {
2296
                        $that->assertEquals($contentCreateStruct, func_get_arg(2));
2297
2298
                        return true;
2299
                    }
2300
                )
2301
            );
2302
2303
        $domainMapperMock->expects($this->once())
2304
            ->method('getUniqueHash')
2305
            ->with($this->isInstanceOf(APIContentCreateStruct::class))
2306
            ->will(
2307
                $this->returnCallback(
2308
                    function ($object) use ($that, $contentCreateStruct) {
2309
                        $that->assertEquals($contentCreateStruct, $object);
2310
2311
                        return 'hash';
2312
                    }
2313
                )
2314
            );
2315
2316
        $this->getFieldTypeRegistryMock()->expects($this->any())
2317
            ->method('getFieldType')
2318
            ->will($this->returnValue($fieldTypeMock));
2319
2320
        $relationProcessorMock
2321
            ->expects($this->any())
2322
            ->method('appendFieldRelations')
2323
            ->with(
2324
                $this->isType('array'),
2325
                $this->isType('array'),
2326
                $this->isInstanceOf(SPIFieldType::class),
2327
                $this->isInstanceOf(Value::class),
2328
                $this->anything()
2329
            );
2330
2331
        $fieldValues = $this->determineValuesForCreate(
2332
            $mainLanguageCode,
2333
            $structFields,
2334
            $fieldDefinitions,
2335
            $languageCodes
2336
        );
2337
        $allFieldErrors = [];
2338
        $validateCount = 0;
2339
        $emptyValue = self::EMPTY_FIELD_VALUE;
2340
        foreach ($contentType->getFieldDefinitions() as $fieldDefinition) {
2341
            foreach ($fieldValues[$fieldDefinition->identifier] as $languageCode => $value) {
2342
                $fieldTypeMock->expects($this->at($validateCount++))
2343
                    ->method('acceptValue')
2344
                    ->will(
2345
                        $this->returnCallback(
2346
                            function ($valueString) {
2347
                                return new ValueStub($valueString);
2348
                            }
2349
                        )
2350
                    );
2351
2352
                $fieldTypeMock->expects($this->at($validateCount++))
2353
                    ->method('isEmptyValue')
2354
                    ->will(
2355
                        $this->returnCallback(
2356
                            function (ValueStub $value) use ($emptyValue) {
2357
                                return $emptyValue === (string)$value;
2358
                            }
2359
                        )
2360
                    );
2361
2362
                if (self::EMPTY_FIELD_VALUE === (string)$value) {
2363
                    continue;
2364
                }
2365
2366
                $fieldTypeMock->expects($this->at($validateCount++))
2367
                    ->method('validate')
2368
                    ->with(
2369
                        $this->equalTo($fieldDefinition),
2370
                        $this->equalTo($value)
2371
                    )->will($this->returnArgument(1));
2372
2373
                $allFieldErrors[$fieldDefinition->id][$languageCode] = $value;
2374
            }
2375
        }
2376
2377
        return [$contentCreateStruct, $allFieldErrors];
2378
    }
2379
2380
    public function providerForTestCreateContentThrowsContentFieldValidationException()
2381
    {
2382
        return $this->providerForTestCreateContentNonRedundantFieldSetComplex();
2383
    }
2384
2385
    /**
2386
     * Test for the createContent() method.
2387
     *
2388
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
2389
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForCreate
2390
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
2391
     * @dataProvider providerForTestCreateContentThrowsContentFieldValidationException
2392
     */
2393 View Code Duplication
    public function testCreateContentThrowsContentFieldValidationException($mainLanguageCode, $structFields)
2394
    {
2395
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\ContentFieldValidationException::class);
2396
        $this->expectExceptionMessage('Content fields did not validate');
2397
2398
        $fieldDefinitions = $this->fixturesForTestCreateContentNonRedundantFieldSetComplex();
2399
        list($contentCreateStruct, $allFieldErrors) =
2400
            $this->assertForTestCreateContentThrowsContentFieldValidationException(
2401
                $mainLanguageCode,
2402
                $structFields,
2403
                $fieldDefinitions
2404
            );
2405
2406
        $mockedService = $this->getPartlyMockedContentService();
2407
2408
        try {
2409
            $mockedService->createContent($contentCreateStruct);
2410
        } catch (ContentFieldValidationException $e) {
2411
            $this->assertEquals($allFieldErrors, $e->getFieldErrors());
2412
            throw $e;
2413
        }
2414
    }
2415
2416
    /**
2417
     * Test for the createContent() method.
2418
     *
2419
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
2420
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForCreate
2421
     * @covers \eZ\Publish\Core\Repository\ContentService::buildSPILocationCreateStructs
2422
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
2423
     */
2424
    public function testCreateContentWithLocations()
2425
    {
2426
        $spiFields = [
2427
            new SPIField(
2428
                [
2429
                    'fieldDefinitionId' => 'fieldDefinitionId',
2430
                    'type' => 'fieldTypeIdentifier',
2431
                    'value' => 'defaultValue',
2432
                    'languageCode' => 'eng-US',
2433
                ]
2434
            ),
2435
        ];
2436
        $fieldDefinitions = [
2437
            new FieldDefinition(
2438
                [
2439
                    'id' => 'fieldDefinitionId',
2440
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
2441
                    'isTranslatable' => false,
2442
                    'identifier' => 'identifier',
2443
                    'isRequired' => false,
2444
                    'defaultValue' => 'defaultValue',
2445
                ]
2446
            ),
2447
        ];
2448
2449
        // Set up a simple case that will pass
2450
        $locationCreateStruct1 = new LocationCreateStruct(['parentLocationId' => 321]);
2451
        $locationCreateStruct2 = new LocationCreateStruct(['parentLocationId' => 654]);
2452
        $locationCreateStructs = [$locationCreateStruct1, $locationCreateStruct2];
2453
        $contentCreateStruct = $this->assertForTestCreateContentNonRedundantFieldSet(
2454
            'eng-US',
2455
            [],
2456
            $spiFields,
2457
            $fieldDefinitions,
2458
            $locationCreateStructs,
2459
            false,
2460
            // Do not execute
2461
            false
2462
        );
2463
2464
        $repositoryMock = $this->getRepositoryMock();
2465
        $mockedService = $this->getPartlyMockedContentService();
2466
        $locationServiceMock = $this->getLocationServiceMock();
2467
        /** @var \PHPUnit\Framework\MockObject\MockObject $handlerMock */
2468
        $handlerMock = $this->getPersistenceMock()->contentHandler();
2469
        $domainMapperMock = $this->getDomainMapperMock();
2470
        $spiLocationCreateStruct = new SPILocation\CreateStruct();
2471
        $parentLocation = new Location(['contentInfo' => new ContentInfo(['sectionId' => 1])]);
2472
2473
        $locationServiceMock->expects($this->at(0))
2474
            ->method('loadLocation')
2475
            ->with($this->equalTo(321))
2476
            ->will($this->returnValue($parentLocation));
2477
2478
        $locationServiceMock->expects($this->at(1))
2479
            ->method('loadLocation')
2480
            ->with($this->equalTo(654))
2481
            ->will($this->returnValue($parentLocation));
2482
2483
        $repositoryMock->expects($this->atLeastOnce())
2484
            ->method('getLocationService')
2485
            ->will($this->returnValue($locationServiceMock));
2486
2487
        $domainMapperMock->expects($this->at(1))
2488
            ->method('buildSPILocationCreateStruct')
2489
            ->with(
2490
                $this->equalTo($locationCreateStruct1),
2491
                $this->equalTo($parentLocation),
2492
                $this->equalTo(true),
2493
                $this->equalTo(null),
2494
                $this->equalTo(null)
2495
            )->will($this->returnValue($spiLocationCreateStruct));
2496
2497
        $domainMapperMock->expects($this->at(2))
2498
            ->method('buildSPILocationCreateStruct')
2499
            ->with(
2500
                $this->equalTo($locationCreateStruct2),
2501
                $this->equalTo($parentLocation),
2502
                $this->equalTo(false),
2503
                $this->equalTo(null),
2504
                $this->equalTo(null)
2505
            )->will($this->returnValue($spiLocationCreateStruct));
2506
2507
        $spiContentCreateStruct = new SPIContentCreateStruct(
2508
            [
2509
                'name' => [],
2510
                'typeId' => 123,
2511
                'sectionId' => 1,
2512
                'ownerId' => 169,
2513
                'remoteId' => 'hash',
2514
                'fields' => $spiFields,
2515
                'modified' => time(),
2516
                'initialLanguageId' => 4242,
2517
                'locations' => [$spiLocationCreateStruct, $spiLocationCreateStruct],
2518
            ]
2519
        );
2520
        $spiContentCreateStruct2 = clone $spiContentCreateStruct;
2521
        ++$spiContentCreateStruct2->modified;
2522
2523
        $spiContent = new SPIContent(
2524
            [
2525
                'versionInfo' => new SPIContent\VersionInfo(
2526
                    [
2527
                        'contentInfo' => new SPIContent\ContentInfo(['id' => 42]),
2528
                        'versionNo' => 7,
2529
                    ]
2530
                ),
2531
            ]
2532
        );
2533
2534
        $handlerMock->expects($this->once())
2535
            ->method('create')
2536
            ->with($this->logicalOr($spiContentCreateStruct, $spiContentCreateStruct2))
2537
            ->will($this->returnValue($spiContent));
2538
2539
        $domainMapperMock->expects($this->once())
2540
            ->method('buildContentDomainObject')
2541
            ->with(
2542
                $this->isInstanceOf(SPIContent::class),
2543
                $this->isInstanceOf(APIContentType::class)
2544
            );
2545
2546
        $repositoryMock->expects($this->once())->method('commit');
2547
2548
        // Execute
2549
        $mockedService->createContent($contentCreateStruct, $locationCreateStructs);
2550
    }
2551
2552
    /**
2553
     * Test for the createContent() method.
2554
     *
2555
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
2556
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForCreate
2557
     * @covers \eZ\Publish\Core\Repository\ContentService::buildSPILocationCreateStructs
2558
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
2559
     */
2560
    public function testCreateContentWithLocationsDuplicateUnderParent()
2561
    {
2562
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\InvalidArgumentException::class);
2563
        $this->expectExceptionMessage('Multiple LocationCreateStructs with the same parent Location \'321\' are given');
2564
2565
        $fieldDefinitions = [
2566
            new FieldDefinition(
2567
                [
2568
                    'id' => 'fieldDefinitionId',
2569
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
2570
                    'isTranslatable' => false,
2571
                    'identifier' => 'identifier',
2572
                    'isRequired' => false,
2573
                    'defaultValue' => 'defaultValue',
2574
                ]
2575
            ),
2576
        ];
2577
2578
        $repositoryMock = $this->getRepositoryMock();
2579
        $mockedService = $this->getPartlyMockedContentService();
2580
        $locationServiceMock = $this->getLocationServiceMock();
2581
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
2582
        $domainMapperMock = $this->getDomainMapperMock();
2583
        $permissionResolver = $this->getPermissionResolverMock();
2584
        /** @var \PHPUnit\Framework\MockObject\MockObject $languageHandlerMock */
2585
        $languageHandlerMock = $this->getPersistenceMock()->contentLanguageHandler();
2586
        $spiLocationCreateStruct = new SPILocation\CreateStruct();
2587
        $parentLocation = new Location(['id' => 321]);
2588
        $locationCreateStruct = new LocationCreateStruct(['parentLocationId' => 321]);
2589
        $locationCreateStructs = [$locationCreateStruct, clone $locationCreateStruct];
2590
        $contentType = new ContentType(
2591
            [
2592
                'id' => 123,
2593
                'fieldDefinitions' => $fieldDefinitions,
2594
                'nameSchema' => '<nameSchema>',
2595
            ]
2596
        );
2597
        $contentCreateStruct = new ContentCreateStruct(
2598
            [
2599
                'fields' => [],
2600
                'mainLanguageCode' => 'eng-US',
2601
                'contentType' => $contentType,
2602
                'alwaysAvailable' => false,
2603
                'ownerId' => 169,
2604
                'sectionId' => 1,
2605
            ]
2606
        );
2607
2608
        $languageHandlerMock->expects($this->any())
2609
            ->method('loadByLanguageCode')
2610
            ->with($this->isType('string'))
2611
            ->will(
2612
                $this->returnCallback(
2613
                    function () {
2614
                        return new Language(['id' => 4242]);
2615
                    }
2616
                )
2617
            );
2618
2619
        $contentTypeServiceMock->expects($this->once())
2620
            ->method('loadContentType')
2621
            ->with($this->equalTo($contentType->id))
2622
            ->will($this->returnValue($contentType));
2623
2624
        $repositoryMock->expects($this->once())
2625
            ->method('getContentTypeService')
2626
            ->will($this->returnValue($contentTypeServiceMock));
2627
2628
        $that = $this;
2629
        $permissionResolver->expects($this->once())
2630
            ->method('canUser')
2631
            ->with(
2632
                $this->equalTo('content'),
2633
                $this->equalTo('create'),
2634
                $this->isInstanceOf(APIContentCreateStruct::class),
2635
                $this->equalTo($locationCreateStructs)
2636
            )->will(
2637
                $this->returnCallback(
2638
                    function () use ($that, $contentCreateStruct) {
2639
                        $that->assertEquals($contentCreateStruct, func_get_arg(2));
2640
2641
                        return true;
2642
                    }
2643
                )
2644
            );
2645
2646
        $domainMapperMock->expects($this->once())
2647
            ->method('getUniqueHash')
2648
            ->with($this->isInstanceOf(APIContentCreateStruct::class))
2649
            ->will(
2650
                $this->returnCallback(
2651
                    function ($object) use ($that, $contentCreateStruct) {
2652
                        $that->assertEquals($contentCreateStruct, $object);
2653
2654
                        return 'hash';
2655
                    }
2656
                )
2657
            );
2658
2659
        $locationServiceMock->expects($this->once())
2660
            ->method('loadLocation')
2661
            ->with($this->equalTo(321))
2662
            ->will($this->returnValue($parentLocation));
2663
2664
        $repositoryMock->expects($this->any())
2665
            ->method('getLocationService')
2666
            ->will($this->returnValue($locationServiceMock));
2667
2668
        $domainMapperMock->expects($this->any())
2669
            ->method('buildSPILocationCreateStruct')
2670
            ->with(
2671
                $this->equalTo($locationCreateStruct),
2672
                $this->equalTo($parentLocation),
2673
                $this->equalTo(true),
2674
                $this->equalTo(null),
2675
                $this->equalTo(null)
2676
            )->will($this->returnValue($spiLocationCreateStruct));
2677
2678
        $mockedService->createContent(
2679
            $contentCreateStruct,
2680
            $locationCreateStructs
2681
        );
2682
    }
2683
2684
    /**
2685
     * Test for the createContent() method.
2686
     *
2687
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
2688
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForCreate
2689
     * @covers \eZ\Publish\Core\Repository\ContentService::getDefaultObjectStates
2690
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
2691
     */
2692
    public function testCreateContentObjectStates()
2693
    {
2694
        $spiFields = [
2695
            new SPIField(
2696
                [
2697
                    'fieldDefinitionId' => 'fieldDefinitionId',
2698
                    'type' => 'fieldTypeIdentifier',
2699
                    'value' => 'defaultValue',
2700
                    'languageCode' => 'eng-US',
2701
                ]
2702
            ),
2703
        ];
2704
        $fieldDefinitions = [
2705
            new FieldDefinition(
2706
                [
2707
                    'id' => 'fieldDefinitionId',
2708
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
2709
                    'isTranslatable' => false,
2710
                    'identifier' => 'identifier',
2711
                    'isRequired' => false,
2712
                    'defaultValue' => 'defaultValue',
2713
                ]
2714
            ),
2715
        ];
2716
        $objectStateGroups = [
0 ignored issues
show
Unused Code introduced by
$objectStateGroups is not used, you could remove the assignment.

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

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

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

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

Loading history...
2717
            new SPIObjectStateGroup(['id' => 10]),
2718
            new SPIObjectStateGroup(['id' => 20]),
2719
        ];
2720
2721
        // Set up a simple case that will pass
2722
        $contentCreateStruct = $this->assertForTestCreateContentNonRedundantFieldSet(
2723
            'eng-US',
2724
            [],
2725
            $spiFields,
2726
            $fieldDefinitions,
2727
            [],
2728
            true,
2729
            // Do not execute
2730
            false
2731
        );
2732
        $timestamp = time();
2733
        $contentCreateStruct->modificationDate = new \DateTime("@{$timestamp}");
2734
2735
        $repositoryMock = $this->getRepositoryMock();
2736
        $mockedService = $this->getPartlyMockedContentService();
2737
        /** @var \PHPUnit\Framework\MockObject\MockObject $handlerMock */
2738
        $handlerMock = $this->getPersistenceMock()->contentHandler();
2739
        $domainMapperMock = $this->getDomainMapperMock();
2740
2741
        $this->mockGetDefaultObjectStates();
2742
        $this->mockSetDefaultObjectStates();
2743
2744
        $spiContentCreateStruct = new SPIContentCreateStruct(
2745
            [
2746
                'name' => [],
2747
                'typeId' => 123,
2748
                'sectionId' => 1,
2749
                'ownerId' => 169,
2750
                'remoteId' => 'hash',
2751
                'fields' => $spiFields,
2752
                'modified' => $timestamp,
2753
                'initialLanguageId' => 4242,
2754
                'locations' => [],
2755
            ]
2756
        );
2757
        $spiContentCreateStruct2 = clone $spiContentCreateStruct;
2758
        ++$spiContentCreateStruct2->modified;
2759
2760
        $spiContent = new SPIContent(
2761
            [
2762
                'versionInfo' => new SPIContent\VersionInfo(
2763
                    [
2764
                        'contentInfo' => new SPIContent\ContentInfo(['id' => 42]),
2765
                        'versionNo' => 7,
2766
                    ]
2767
                ),
2768
            ]
2769
        );
2770
2771
        $handlerMock->expects($this->once())
2772
            ->method('create')
2773
            ->with($this->equalTo($spiContentCreateStruct))
2774
            ->will($this->returnValue($spiContent));
2775
2776
        $domainMapperMock->expects($this->once())
2777
            ->method('buildContentDomainObject')
2778
            ->with(
2779
                $this->isInstanceOf(SPIContent::class),
2780
                $this->isInstanceOf(APIContentType::class)
2781
            );
2782
2783
        $repositoryMock->expects($this->once())->method('commit');
2784
2785
        // Execute
2786
        $mockedService->createContent($contentCreateStruct, []);
2787
    }
2788
2789
    /**
2790
     * Test for the createContent() method.
2791
     *
2792
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
2793
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForCreate
2794
     * @covers \eZ\Publish\Core\Repository\ContentService::getDefaultObjectStates
2795
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
2796
     * @dataProvider providerForTestCreateContentThrowsContentValidationExceptionTranslation
2797
     */
2798
    public function testCreateContentWithRollback()
2799
    {
2800
        $this->expectException(\Exception::class);
2801
        $this->expectExceptionMessage('Store failed');
2802
2803
        $fieldDefinitions = [
2804
            new FieldDefinition(
2805
                [
2806
                    'id' => 'fieldDefinitionId',
2807
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
2808
                    'isTranslatable' => false,
2809
                    'identifier' => 'identifier',
2810
                    'isRequired' => false,
2811
                    'defaultValue' => 'defaultValue',
2812
                ]
2813
            ),
2814
        ];
2815
2816
        // Setup a simple case that will pass
2817
        $contentCreateStruct = $this->assertForTestCreateContentNonRedundantFieldSet(
2818
            'eng-US',
2819
            [],
2820
            [],
2821
            $fieldDefinitions,
2822
            [],
2823
            false,
2824
            // Do not execute test
2825
            false
2826
        );
2827
2828
        $repositoryMock = $this->getRepositoryMock();
2829
        $repositoryMock->expects($this->never())->method('commit');
2830
        $repositoryMock->expects($this->once())->method('rollback');
2831
2832
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandlerMock */
2833
        $contentHandlerMock = $this->getPersistenceMock()->contentHandler();
2834
        $contentHandlerMock->expects($this->once())
2835
            ->method('create')
2836
            ->with($this->anything())
2837
            ->will($this->throwException(new \Exception('Store failed')));
2838
2839
        // Execute
2840
        $this->partlyMockedContentService->createContent($contentCreateStruct, []);
2841
    }
2842
2843
    public function providerForTestUpdateContentThrowsBadStateException()
2844
    {
2845
        return [
2846
            [VersionInfo::STATUS_PUBLISHED],
2847
            [VersionInfo::STATUS_ARCHIVED],
2848
        ];
2849
    }
2850
2851
    /**
2852
     * Test for the updateContent() method.
2853
     *
2854
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContent
2855
     * @dataProvider providerForTestUpdateContentThrowsBadStateException
2856
     */
2857
    public function testUpdateContentThrowsBadStateException($status)
2858
    {
2859
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\BadStateException::class);
2860
2861
        $mockedService = $this->getPartlyMockedContentService(['loadContent']);
2862
        $contentUpdateStruct = new ContentUpdateStruct();
2863
        $versionInfo = new VersionInfo(
2864
            [
2865
                'contentInfo' => new ContentInfo(['id' => 42]),
2866
                'versionNo' => 7,
2867
                'status' => $status,
2868
            ]
2869
        );
2870
        $content = new Content(
2871
            [
2872
                'versionInfo' => $versionInfo,
2873
                'internalFields' => [],
2874
            ]
2875
        );
2876
2877
        $mockedService->expects($this->once())
2878
            ->method('loadContent')
2879
            ->with(
2880
                $this->equalTo(42),
2881
                $this->equalTo(null),
2882
                $this->equalTo(7)
2883
            )->will(
2884
                $this->returnValue($content)
2885
            );
2886
2887
        $mockedService->updateContent($versionInfo, $contentUpdateStruct);
2888
    }
2889
2890
    /**
2891
     * Test for the updateContent() method.
2892
     *
2893
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContent
2894
     */
2895
    public function testUpdateContentThrowsUnauthorizedException()
2896
    {
2897
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\UnauthorizedException::class);
2898
2899
        $permissionResolverMock = $this->getPermissionResolverMock();
2900
        $mockedService = $this->getPartlyMockedContentService(['loadContent']);
2901
        $contentUpdateStruct = new ContentUpdateStruct();
2902
        $versionInfo = new VersionInfo(
2903
            [
2904
                'contentInfo' => new ContentInfo(['id' => 42]),
2905
                'versionNo' => 7,
2906
                'status' => VersionInfo::STATUS_DRAFT,
2907
            ]
2908
        );
2909
        $content = new Content(
2910
            [
2911
                'versionInfo' => $versionInfo,
2912
                'internalFields' => [],
2913
            ]
2914
        );
2915
2916
        $mockedService->expects($this->once())
2917
            ->method('loadContent')
2918
            ->with(
2919
                $this->equalTo(42),
2920
                $this->equalTo(null),
2921
                $this->equalTo(7)
2922
            )->will(
2923
                $this->returnValue($content)
2924
            );
2925
2926
        $permissionResolverMock->expects($this->once())
2927
            ->method('canUser')
2928
            ->with(
2929
                $this->equalTo('content'),
2930
                $this->equalTo('edit'),
2931
                $this->equalTo($content),
2932
                $this->isType('array')
2933
            )->will($this->returnValue(false));
2934
2935
        $mockedService->updateContent($versionInfo, $contentUpdateStruct);
2936
    }
2937
2938
    /**
2939
     * @param string $initialLanguageCode
2940
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $structFields
2941
     * @param string[] $existingLanguages
2942
     *
2943
     * @return string[]
2944
     */
2945
    protected function determineLanguageCodesForUpdate($initialLanguageCode, array $structFields, $existingLanguages)
2946
    {
2947
        $languageCodes = array_fill_keys($existingLanguages, true);
2948
        if ($initialLanguageCode !== null) {
2949
            $languageCodes[$initialLanguageCode] = true;
2950
        }
2951
2952
        foreach ($structFields as $field) {
2953
            if ($field->languageCode === null || isset($languageCodes[$field->languageCode])) {
2954
                continue;
2955
            }
2956
2957
            $languageCodes[$field->languageCode] = true;
2958
        }
2959
2960
        return array_keys($languageCodes);
2961
    }
2962
2963
    /**
2964
     * @param string $initialLanguageCode
2965
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $structFields
2966
     * @param string $mainLanguageCode
2967
     * @param \eZ\Publish\API\Repository\Values\ContentType\FieldDefinition[] $fieldDefinitions
2968
     *
2969
     * @return array
2970
     */
2971
    protected function mapStructFieldsForUpdate($initialLanguageCode, $structFields, $mainLanguageCode, $fieldDefinitions)
2972
    {
2973
        $initialLanguageCode = $initialLanguageCode ?: $mainLanguageCode;
2974
2975
        $mappedFieldDefinitions = [];
2976
        foreach ($fieldDefinitions as $fieldDefinition) {
2977
            $mappedFieldDefinitions[$fieldDefinition->identifier] = $fieldDefinition;
2978
        }
2979
2980
        $mappedStructFields = [];
2981
        foreach ($structFields as $structField) {
2982
            $identifier = $structField->fieldDefIdentifier;
2983
2984
            if ($structField->languageCode !== null) {
2985
                $languageCode = $structField->languageCode;
2986
            } elseif ($mappedFieldDefinitions[$identifier]->isTranslatable) {
2987
                $languageCode = $initialLanguageCode;
2988
            } else {
2989
                $languageCode = $mainLanguageCode;
2990
            }
2991
2992
            $mappedStructFields[$identifier][$languageCode] = (string)$structField->value;
2993
        }
2994
2995
        return $mappedStructFields;
2996
    }
2997
2998
    /**
2999
     * Returns full, possibly redundant array of field values, indexed by field definition
3000
     * identifier and language code.
3001
     *
3002
     * @param string $initialLanguageCode
3003
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $structFields
3004
     * @param \eZ\Publish\Core\Repository\Values\Content\Content $content
3005
     * @param \eZ\Publish\API\Repository\Values\ContentType\FieldDefinition[] $fieldDefinitions
3006
     * @param array $languageCodes
3007
     *
3008
     * @return array
3009
     */
3010
    protected function determineValuesForUpdate(
3011
        $initialLanguageCode,
3012
        array $structFields,
3013
        Content $content,
3014
        array $fieldDefinitions,
3015
        array $languageCodes
3016
    ) {
3017
        $mainLanguageCode = $content->versionInfo->contentInfo->mainLanguageCode;
3018
3019
        $mappedStructFields = $this->mapStructFieldsForUpdate(
3020
            $initialLanguageCode,
3021
            $structFields,
3022
            $mainLanguageCode,
3023
            $fieldDefinitions
3024
        );
3025
3026
        $values = [];
3027
3028
        foreach ($fieldDefinitions as $fieldDefinition) {
3029
            $identifier = $fieldDefinition->identifier;
3030
            foreach ($languageCodes as $languageCode) {
3031 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...
3032
                    if (isset($mappedStructFields[$identifier][$mainLanguageCode])) {
3033
                        $values[$identifier][$languageCode] = $mappedStructFields[$identifier][$mainLanguageCode];
3034
                    } else {
3035
                        $values[$identifier][$languageCode] = (string)$content->fields[$identifier][$mainLanguageCode];
3036
                    }
3037
                    continue;
3038
                }
3039
3040 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...
3041
                    $values[$identifier][$languageCode] = $mappedStructFields[$identifier][$languageCode];
3042
                    continue;
3043
                }
3044
3045
                if (isset($content->fields[$identifier][$languageCode])) {
3046
                    $values[$identifier][$languageCode] = (string)$content->fields[$identifier][$languageCode];
3047
                    continue;
3048
                }
3049
3050
                $values[$identifier][$languageCode] = (string)$fieldDefinition->defaultValue;
3051
            }
3052
        }
3053
3054
        return $this->stubValues($values);
3055
    }
3056
3057
    protected function stubValues(array $fieldValues)
3058
    {
3059
        foreach ($fieldValues as &$languageValues) {
3060
            foreach ($languageValues as &$value) {
3061
                $value = new ValueStub($value);
3062
            }
3063
        }
3064
3065
        return $fieldValues;
3066
    }
3067
3068
    /**
3069
     * Asserts that calling updateContent() with given API field set causes calling
3070
     * Handler::updateContent() with given SPI field set.
3071
     *
3072
     * @param string $initialLanguageCode
3073
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $structFields
3074
     * @param \eZ\Publish\SPI\Persistence\Content\Field[] $spiFields
3075
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $existingFields
3076
     * @param \eZ\Publish\API\Repository\Values\ContentType\FieldDefinition[] $fieldDefinitions
3077
     * @param bool $execute
3078
     *
3079
     * @return mixed
3080
     */
3081
    protected function assertForTestUpdateContentNonRedundantFieldSet(
3082
        $initialLanguageCode,
3083
        array $structFields,
3084
        array $spiFields,
3085
        array $existingFields,
3086
        array $fieldDefinitions,
3087
        $execute = true
3088
    ) {
3089
        $repositoryMock = $this->getRepositoryMock();
3090
        $permissionResolverMock = $this->getPermissionResolverMock();
3091
        $permissionResolverMock
3092
            ->expects($this->once())
3093
            ->method('getCurrentUserReference')
3094
            ->willReturn(new UserReference(169));
3095
        $mockedService = $this->getPartlyMockedContentService(['loadContent', 'loadRelations'], $permissionResolverMock);
3096
        $permissionResolverMock = $this->getPermissionResolverMock();
3097
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandlerMock */
3098
        $contentHandlerMock = $this->getPersistenceMock()->contentHandler();
3099
        /** @var \PHPUnit\Framework\MockObject\MockObject $languageHandlerMock */
3100
        $languageHandlerMock = $this->getPersistenceMock()->contentLanguageHandler();
3101
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
3102
        $domainMapperMock = $this->getDomainMapperMock();
3103
        $relationProcessorMock = $this->getRelationProcessorMock();
3104
        $nameSchemaServiceMock = $this->getNameSchemaServiceMock();
3105
        $fieldTypeMock = $this->createMock(SPIFieldType::class);
3106
        $existingLanguageCodes = array_map(
3107
            function (Field $field) {
3108
                return $field->languageCode;
3109
            },
3110
            $existingFields
3111
        );
3112
        $languageCodes = $this->determineLanguageCodesForUpdate(
3113
            $initialLanguageCode,
3114
            $structFields,
3115
            $existingLanguageCodes
3116
        );
3117
        $versionInfo = new VersionInfo(
3118
            [
3119
                'contentInfo' => new ContentInfo(
3120
                    [
3121
                        'id' => 42,
3122
                        'contentTypeId' => 24,
3123
                        'mainLanguageCode' => 'eng-GB',
3124
                    ]
3125
                ),
3126
                'versionNo' => 7,
3127
                'languageCodes' => $existingLanguageCodes,
3128
                'status' => VersionInfo::STATUS_DRAFT,
3129
            ]
3130
        );
3131
        $content = new Content(
3132
            [
3133
                'versionInfo' => $versionInfo,
3134
                'internalFields' => $existingFields,
3135
            ]
3136
        );
3137
        $contentType = new ContentType(['fieldDefinitions' => $fieldDefinitions]);
3138
3139
        $languageHandlerMock->expects($this->any())
3140
            ->method('loadByLanguageCode')
3141
            ->with($this->isType('string'))
3142
            ->will(
3143
                $this->returnCallback(
3144
                    function () {
3145
                        return new Language(['id' => 4242]);
3146
                    }
3147
                )
3148
            );
3149
3150
        $mockedService->expects($this->once())
3151
            ->method('loadContent')
3152
            ->with(
3153
                $this->equalTo(42),
3154
                $this->equalTo(null),
3155
                $this->equalTo(7)
3156
            )->will(
3157
                $this->returnValue($content)
3158
            );
3159
3160
        $repositoryMock->expects($this->once())->method('beginTransaction');
3161
3162
        $permissionResolverMock->expects($this->once())
3163
            ->method('canUser')
3164
            ->with(
3165
                $this->equalTo('content'),
3166
                $this->equalTo('edit'),
3167
                $this->equalTo($content),
3168
                $this->isType('array')
3169
            )->will($this->returnValue(true));
3170
3171
        $contentTypeServiceMock->expects($this->once())
3172
            ->method('loadContentType')
3173
            ->with($this->equalTo(24))
3174
            ->will($this->returnValue($contentType));
3175
3176
        $repositoryMock->expects($this->once())
3177
            ->method('getContentTypeService')
3178
            ->will($this->returnValue($contentTypeServiceMock));
3179
3180
        $fieldTypeMock->expects($this->any())
3181
            ->method('acceptValue')
3182
            ->will(
3183
                $this->returnCallback(
3184
                    function ($valueString) {
3185
                        return new ValueStub($valueString);
3186
                    }
3187
                )
3188
            );
3189
3190
        $emptyValue = self::EMPTY_FIELD_VALUE;
3191
        $fieldTypeMock->expects($this->any())
3192
            ->method('toPersistenceValue')
3193
            ->will(
3194
                $this->returnCallback(
3195
                    function (ValueStub $value) {
3196
                        return (string)$value;
3197
                    }
3198
                )
3199
            );
3200
3201
        $fieldTypeMock->expects($this->any())
3202
            ->method('isEmptyValue')
3203
            ->will(
3204
                $this->returnCallback(
3205
                    function (ValueStub $value) use ($emptyValue) {
3206
                        return $emptyValue === (string)$value;
3207
                    }
3208
                )
3209
            );
3210
3211
        $fieldTypeMock->expects($this->any())
3212
            ->method('validate')
3213
            ->will($this->returnValue([]));
3214
3215
        $this->getFieldTypeRegistryMock()->expects($this->any())
3216
            ->method('getFieldType')
3217
            ->will($this->returnValue($fieldTypeMock));
3218
3219
        $relationProcessorMock
3220
            ->expects($this->exactly(count($fieldDefinitions) * count($languageCodes)))
3221
            ->method('appendFieldRelations')
3222
            ->with(
3223
                $this->isType('array'),
3224
                $this->isType('array'),
3225
                $this->isInstanceOf(SPIFieldType::class),
3226
                $this->isInstanceOf(Value::class),
3227
                $this->anything()
3228
            );
3229
3230
        $values = $this->determineValuesForUpdate(
3231
            $initialLanguageCode,
3232
            $structFields,
3233
            $content,
3234
            $fieldDefinitions,
3235
            $languageCodes
3236
        );
3237
        $nameSchemaServiceMock->expects($this->once())
3238
            ->method('resolveNameSchema')
3239
            ->with(
3240
                $this->equalTo($content),
3241
                $this->equalTo($values),
3242
                $this->equalTo($languageCodes)
3243
            )->will($this->returnValue([]));
3244
3245
        $existingRelations = ['RELATIONS!!!'];
3246
        $mockedService->expects($this->once())
3247
            ->method('loadRelations')
3248
            ->with($content->versionInfo)
3249
            ->will($this->returnValue($existingRelations));
3250
        $relationProcessorMock->expects($this->any())
3251
            ->method('processFieldRelations')
3252
            ->with(
3253
                $this->isType('array'),
3254
                $this->equalTo(42),
3255
                $this->isType('int'),
3256
                $this->equalTo($contentType),
3257
                $this->equalTo($existingRelations)
3258
            );
3259
3260
        $contentUpdateStruct = new ContentUpdateStruct(
3261
            [
3262
                'fields' => $structFields,
3263
                'initialLanguageCode' => $initialLanguageCode,
3264
            ]
3265
        );
3266
3267
        if ($execute) {
3268
            $spiContentUpdateStruct = new SPIContentUpdateStruct(
3269
                [
3270
                    'creatorId' => 169,
3271
                    'fields' => $spiFields,
3272
                    'modificationDate' => time(),
3273
                    'initialLanguageId' => 4242,
3274
                ]
3275
            );
3276
3277
            // During code coverage runs, timestamp might differ 1-3 seconds
3278
            $spiContentUpdateStructTs1 = clone $spiContentUpdateStruct;
3279
            ++$spiContentUpdateStructTs1->modificationDate;
3280
3281
            $spiContentUpdateStructTs2 = clone $spiContentUpdateStructTs1;
3282
            ++$spiContentUpdateStructTs2->modificationDate;
3283
3284
            $spiContentUpdateStructTs3 = clone $spiContentUpdateStructTs2;
3285
            ++$spiContentUpdateStructTs3->modificationDate;
3286
3287
            $spiContent = new SPIContent(
3288
                [
3289
                    'versionInfo' => new SPIContent\VersionInfo(
3290
                        [
3291
                            'contentInfo' => new SPIContent\ContentInfo(['id' => 42]),
3292
                            'versionNo' => 7,
3293
                        ]
3294
                    ),
3295
                ]
3296
            );
3297
3298
            $contentHandlerMock->expects($this->once())
3299
                ->method('updateContent')
3300
                ->with(
3301
                    42,
3302
                    7,
3303
                    $this->logicalOr($spiContentUpdateStruct, $spiContentUpdateStructTs1, $spiContentUpdateStructTs2, $spiContentUpdateStructTs3)
3304
                )
3305
                ->will($this->returnValue($spiContent));
3306
3307
            $repositoryMock->expects($this->once())->method('commit');
3308
            $domainMapperMock->expects($this->once())
3309
                ->method('buildContentDomainObject')
3310
                ->with(
3311
                    $this->isInstanceOf(SPIContent::class),
3312
                    $this->isInstanceOf(APIContentType::class)
3313
                );
3314
3315
            $mockedService->updateContent($content->versionInfo, $contentUpdateStruct);
3316
        }
3317
3318
        return [$content->versionInfo, $contentUpdateStruct];
3319
    }
3320
3321
    public function providerForTestUpdateContentNonRedundantFieldSet1()
3322
    {
3323
        $spiFields = [
3324
            new SPIField(
3325
                [
3326
                    'id' => '100',
3327
                    'fieldDefinitionId' => 'fieldDefinitionId',
3328
                    'type' => 'fieldTypeIdentifier',
3329
                    'value' => 'newValue',
3330
                    'languageCode' => 'eng-GB',
3331
                    'versionNo' => 7,
3332
                ]
3333
            ),
3334
        ];
3335
3336
        return [
3337
            // With languages set
3338
            [
3339
                'eng-GB',
3340
                [
3341
                    new Field(
3342
                        [
3343
                            'fieldDefIdentifier' => 'identifier',
3344
                            'value' => 'newValue',
3345
                            'languageCode' => 'eng-GB',
3346
                        ]
3347
                    ),
3348
                ],
3349
                $spiFields,
3350
            ],
3351
            // Without languages set
3352
            [
3353
                null,
3354
                [
3355
                    new Field(
3356
                        [
3357
                            'fieldDefIdentifier' => 'identifier',
3358
                            'value' => 'newValue',
3359
                            'languageCode' => null,
3360
                        ]
3361
                    ),
3362
                ],
3363
                $spiFields,
3364
            ],
3365
            // Adding new language without fields
3366
            [
3367
                'eng-US',
3368
                [],
3369
                [],
3370
            ],
3371
        ];
3372
    }
3373
3374
    /**
3375
     * Test for the updateContent() method.
3376
     *
3377
     * Testing the simplest use case.
3378
     *
3379
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForUpdate
3380
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForUpdate
3381
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContent
3382
     * @dataProvider providerForTestUpdateContentNonRedundantFieldSet1
3383
     */
3384 View Code Duplication
    public function testUpdateContentNonRedundantFieldSet1($initialLanguageCode, $structFields, $spiFields)
3385
    {
3386
        $existingFields = [
3387
            new Field(
3388
                [
3389
                    'id' => '100',
3390
                    'fieldDefIdentifier' => 'identifier',
3391
                    'value' => 'initialValue',
3392
                    'languageCode' => 'eng-GB',
3393
                ]
3394
            ),
3395
        ];
3396
3397
        $fieldDefinitions = [
3398
            new FieldDefinition(
3399
                [
3400
                    'id' => 'fieldDefinitionId',
3401
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
3402
                    'isTranslatable' => false,
3403
                    'identifier' => 'identifier',
3404
                    'isRequired' => false,
3405
                    'defaultValue' => 'defaultValue',
3406
                ]
3407
            ),
3408
        ];
3409
3410
        $this->assertForTestUpdateContentNonRedundantFieldSet(
3411
            $initialLanguageCode,
3412
            $structFields,
3413
            $spiFields,
3414
            $existingFields,
3415
            $fieldDefinitions
3416
        );
3417
    }
3418
3419
    public function providerForTestUpdateContentNonRedundantFieldSet2()
3420
    {
3421
        $spiFields0 = [
3422
            new SPIField(
3423
                [
3424
                    'id' => '100',
3425
                    'fieldDefinitionId' => 'fieldDefinitionId',
3426
                    'type' => 'fieldTypeIdentifier',
3427
                    'value' => 'newValue',
3428
                    'languageCode' => 'eng-GB',
3429
                    'versionNo' => 7,
3430
                ]
3431
            ),
3432
        ];
3433
        $spiFields1 = [
3434
            new SPIField(
3435
                [
3436
                    'id' => null,
3437
                    'fieldDefinitionId' => 'fieldDefinitionId',
3438
                    'type' => 'fieldTypeIdentifier',
3439
                    'value' => 'newValue',
3440
                    'languageCode' => 'eng-US',
3441
                    'versionNo' => 7,
3442
                ]
3443
            ),
3444
        ];
3445
        $spiFields2 = [
3446
            new SPIField(
3447
                [
3448
                    'id' => 100,
3449
                    'fieldDefinitionId' => 'fieldDefinitionId',
3450
                    'type' => 'fieldTypeIdentifier',
3451
                    'value' => 'newValue2',
3452
                    'languageCode' => 'eng-GB',
3453
                    'versionNo' => 7,
3454
                ]
3455
            ),
3456
            new SPIField(
3457
                [
3458
                    'id' => null,
3459
                    'fieldDefinitionId' => 'fieldDefinitionId',
3460
                    'type' => 'fieldTypeIdentifier',
3461
                    'value' => 'newValue1',
3462
                    'languageCode' => 'eng-US',
3463
                    'versionNo' => 7,
3464
                ]
3465
            ),
3466
        ];
3467
3468
        return [
3469
            // 0. With languages set
3470
            [
3471
                'eng-GB',
3472
                [
3473
                    new Field(
3474
                        [
3475
                            'fieldDefIdentifier' => 'identifier',
3476
                            'value' => 'newValue',
3477
                            'languageCode' => 'eng-GB',
3478
                        ]
3479
                    ),
3480
                ],
3481
                $spiFields0,
3482
            ],
3483
            // 1. Without languages set
3484
            [
3485
                null,
3486
                [
3487
                    new Field(
3488
                        [
3489
                            'fieldDefIdentifier' => 'identifier',
3490
                            'value' => 'newValue',
3491
                            'languageCode' => null,
3492
                        ]
3493
                    ),
3494
                ],
3495
                $spiFields0,
3496
            ],
3497
            // 2. New language with language set
3498
            [
3499
                'eng-GB',
3500
                [
3501
                    new Field(
3502
                        [
3503
                            'fieldDefIdentifier' => 'identifier',
3504
                            'value' => 'newValue',
3505
                            'languageCode' => 'eng-US',
3506
                        ]
3507
                    ),
3508
                ],
3509
                $spiFields1,
3510
            ],
3511
            // 3. New language without language set
3512
            [
3513
                'eng-US',
3514
                [
3515
                    new Field(
3516
                        [
3517
                            'fieldDefIdentifier' => 'identifier',
3518
                            'value' => 'newValue',
3519
                            'languageCode' => null,
3520
                        ]
3521
                    ),
3522
                ],
3523
                $spiFields1,
3524
            ],
3525
            // 4. New language and existing language with language set
3526
            [
3527
                'eng-GB',
3528
                [
3529
                    new Field(
3530
                        [
3531
                            'fieldDefIdentifier' => 'identifier',
3532
                            'value' => 'newValue1',
3533
                            'languageCode' => 'eng-US',
3534
                        ]
3535
                    ),
3536
                    new Field(
3537
                        [
3538
                            'fieldDefIdentifier' => 'identifier',
3539
                            'value' => 'newValue2',
3540
                            'languageCode' => 'eng-GB',
3541
                        ]
3542
                    ),
3543
                ],
3544
                $spiFields2,
3545
            ],
3546
            // 5. New language and existing language without language set
3547
            [
3548
                'eng-US',
3549
                [
3550
                    new Field(
3551
                        [
3552
                            'fieldDefIdentifier' => 'identifier',
3553
                            'value' => 'newValue1',
3554
                            'languageCode' => null,
3555
                        ]
3556
                    ),
3557
                    new Field(
3558
                        [
3559
                            'fieldDefIdentifier' => 'identifier',
3560
                            'value' => 'newValue2',
3561
                            'languageCode' => 'eng-GB',
3562
                        ]
3563
                    ),
3564
                ],
3565
                $spiFields2,
3566
            ],
3567
            // 6. Adding new language without fields
3568
            [
3569
                'eng-US',
3570
                [],
3571
                [
3572
                    new SPIField(
3573
                        [
3574
                            'id' => null,
3575
                            'fieldDefinitionId' => 'fieldDefinitionId',
3576
                            'type' => 'fieldTypeIdentifier',
3577
                            'value' => 'defaultValue',
3578
                            'languageCode' => 'eng-US',
3579
                            'versionNo' => 7,
3580
                        ]
3581
                    ),
3582
                ],
3583
            ],
3584
        ];
3585
    }
3586
3587
    /**
3588
     * Test for the updateContent() method.
3589
     *
3590
     * Testing with translatable field.
3591
     *
3592
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForUpdate
3593
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForUpdate
3594
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContent
3595
     * @dataProvider providerForTestUpdateContentNonRedundantFieldSet2
3596
     */
3597 View Code Duplication
    public function testUpdateContentNonRedundantFieldSet2($initialLanguageCode, $structFields, $spiFields)
3598
    {
3599
        $existingFields = [
3600
            new Field(
3601
                [
3602
                    'id' => '100',
3603
                    'fieldDefIdentifier' => 'identifier',
3604
                    'value' => 'initialValue',
3605
                    'languageCode' => 'eng-GB',
3606
                ]
3607
            ),
3608
        ];
3609
3610
        $fieldDefinitions = [
3611
            new FieldDefinition(
3612
                [
3613
                    'id' => 'fieldDefinitionId',
3614
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
3615
                    'isTranslatable' => true,
3616
                    'identifier' => 'identifier',
3617
                    'isRequired' => false,
3618
                    'defaultValue' => 'defaultValue',
3619
                ]
3620
            ),
3621
        ];
3622
3623
        $this->assertForTestUpdateContentNonRedundantFieldSet(
3624
            $initialLanguageCode,
3625
            $structFields,
3626
            $spiFields,
3627
            $existingFields,
3628
            $fieldDefinitions
3629
        );
3630
    }
3631
3632
    public function providerForTestUpdateContentNonRedundantFieldSet3()
3633
    {
3634
        $spiFields0 = [
3635
            new SPIField(
3636
                [
3637
                    'id' => null,
3638
                    'fieldDefinitionId' => 'fieldDefinitionId1',
3639
                    'type' => 'fieldTypeIdentifier',
3640
                    'value' => 'newValue1',
3641
                    'languageCode' => 'eng-US',
3642
                    'versionNo' => 7,
3643
                ]
3644
            ),
3645
        ];
3646
        $spiFields1 = [
3647
            new SPIField(
3648
                [
3649
                    'id' => 100,
3650
                    'fieldDefinitionId' => 'fieldDefinitionId1',
3651
                    'type' => 'fieldTypeIdentifier',
3652
                    'value' => 'newValue2',
3653
                    'languageCode' => 'eng-GB',
3654
                    'versionNo' => 7,
3655
                ]
3656
            ),
3657
            new SPIField(
3658
                [
3659
                    'id' => null,
3660
                    'fieldDefinitionId' => 'fieldDefinitionId1',
3661
                    'type' => 'fieldTypeIdentifier',
3662
                    'value' => 'newValue1',
3663
                    'languageCode' => 'eng-US',
3664
                    'versionNo' => 7,
3665
                ]
3666
            ),
3667
        ];
3668
        $spiFields2 = [
3669
            new SPIField(
3670
                [
3671
                    'id' => 100,
3672
                    'fieldDefinitionId' => 'fieldDefinitionId1',
3673
                    'type' => 'fieldTypeIdentifier',
3674
                    'value' => 'newValue2',
3675
                    'languageCode' => 'eng-GB',
3676
                    'versionNo' => 7,
3677
                ]
3678
            ),
3679
            new SPIField(
3680
                [
3681
                    'id' => null,
3682
                    'fieldDefinitionId' => 'fieldDefinitionId1',
3683
                    'type' => 'fieldTypeIdentifier',
3684
                    'value' => 'newValue1',
3685
                    'languageCode' => 'eng-US',
3686
                    'versionNo' => 7,
3687
                ]
3688
            ),
3689
            new SPIField(
3690
                [
3691
                    'id' => 101,
3692
                    'fieldDefinitionId' => 'fieldDefinitionId2',
3693
                    'type' => 'fieldTypeIdentifier',
3694
                    'value' => 'newValue3',
3695
                    'languageCode' => 'eng-GB',
3696
                    'versionNo' => 7,
3697
                ]
3698
            ),
3699
        ];
3700
        $spiFields3 = [
3701
            new SPIField(
3702
                [
3703
                    'id' => null,
3704
                    'fieldDefinitionId' => 'fieldDefinitionId1',
3705
                    'type' => 'fieldTypeIdentifier',
3706
                    'value' => 'defaultValue1',
3707
                    'languageCode' => 'eng-US',
3708
                    'versionNo' => 7,
3709
                ]
3710
            ),
3711
        ];
3712
3713
        return [
3714
            // 0. ew language with language set
3715
            [
3716
                'eng-US',
3717
                [
3718
                    new Field(
3719
                        [
3720
                            'fieldDefIdentifier' => 'identifier1',
3721
                            'value' => 'newValue1',
3722
                            'languageCode' => 'eng-US',
3723
                        ]
3724
                    ),
3725
                ],
3726
                $spiFields0,
3727
            ],
3728
            // 1. New language without language set
3729
            [
3730
                'eng-US',
3731
                [
3732
                    new Field(
3733
                        [
3734
                            'fieldDefIdentifier' => 'identifier1',
3735
                            'value' => 'newValue1',
3736
                            'languageCode' => null,
3737
                        ]
3738
                    ),
3739
                ],
3740
                $spiFields0,
3741
            ],
3742
            // 2. New language and existing language with language set
3743
            [
3744
                'eng-US',
3745
                [
3746
                    new Field(
3747
                        [
3748
                            'fieldDefIdentifier' => 'identifier1',
3749
                            'value' => 'newValue1',
3750
                            'languageCode' => 'eng-US',
3751
                        ]
3752
                    ),
3753
                    new Field(
3754
                        [
3755
                            'fieldDefIdentifier' => 'identifier1',
3756
                            'value' => 'newValue2',
3757
                            'languageCode' => 'eng-GB',
3758
                        ]
3759
                    ),
3760
                ],
3761
                $spiFields1,
3762
            ],
3763
            // 3. New language and existing language without language set
3764
            [
3765
                'eng-US',
3766
                [
3767
                    new Field(
3768
                        [
3769
                            'fieldDefIdentifier' => 'identifier1',
3770
                            'value' => 'newValue1',
3771
                            'languageCode' => null,
3772
                        ]
3773
                    ),
3774
                    new Field(
3775
                        [
3776
                            'fieldDefIdentifier' => 'identifier1',
3777
                            'value' => 'newValue2',
3778
                            'languageCode' => 'eng-GB',
3779
                        ]
3780
                    ),
3781
                ],
3782
                $spiFields1,
3783
            ],
3784
            // 4. New language and existing language with untranslatable field, with language set
3785
            [
3786
                'eng-US',
3787
                [
3788
                    new Field(
3789
                        [
3790
                            'fieldDefIdentifier' => 'identifier1',
3791
                            'value' => 'newValue1',
3792
                            'languageCode' => 'eng-US',
3793
                        ]
3794
                    ),
3795
                    new Field(
3796
                        [
3797
                            'fieldDefIdentifier' => 'identifier1',
3798
                            'value' => 'newValue2',
3799
                            'languageCode' => 'eng-GB',
3800
                        ]
3801
                    ),
3802
                    new Field(
3803
                        [
3804
                            'fieldDefIdentifier' => 'identifier2',
3805
                            'value' => 'newValue3',
3806
                            'languageCode' => 'eng-GB',
3807
                        ]
3808
                    ),
3809
                ],
3810
                $spiFields2,
3811
            ],
3812
            // 5. New language and existing language with untranslatable field, without language set
3813
            [
3814
                'eng-US',
3815
                [
3816
                    new Field(
3817
                        [
3818
                            'fieldDefIdentifier' => 'identifier1',
3819
                            'value' => 'newValue1',
3820
                            'languageCode' => null,
3821
                        ]
3822
                    ),
3823
                    new Field(
3824
                        [
3825
                            'fieldDefIdentifier' => 'identifier1',
3826
                            'value' => 'newValue2',
3827
                            'languageCode' => 'eng-GB',
3828
                        ]
3829
                    ),
3830
                    new Field(
3831
                        [
3832
                            'fieldDefIdentifier' => 'identifier2',
3833
                            'value' => 'newValue3',
3834
                            'languageCode' => null,
3835
                        ]
3836
                    ),
3837
                ],
3838
                $spiFields2,
3839
            ],
3840
            // 6. Adding new language without fields
3841
            [
3842
                'eng-US',
3843
                [],
3844
                $spiFields3,
3845
            ],
3846
        ];
3847
    }
3848
3849
    /**
3850
     * Test for the updateContent() method.
3851
     *
3852
     * Testing with new language and untranslatable field.
3853
     *
3854
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForUpdate
3855
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForUpdate
3856
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContent
3857
     * @dataProvider providerForTestUpdateContentNonRedundantFieldSet3
3858
     */
3859
    public function testUpdateContentNonRedundantFieldSet3($initialLanguageCode, $structFields, $spiFields)
3860
    {
3861
        $existingFields = [
3862
            new Field(
3863
                [
3864
                    'id' => '100',
3865
                    'fieldDefIdentifier' => 'identifier1',
3866
                    'value' => 'initialValue1',
3867
                    'languageCode' => 'eng-GB',
3868
                ]
3869
            ),
3870
            new Field(
3871
                [
3872
                    'id' => '101',
3873
                    'fieldDefIdentifier' => 'identifier2',
3874
                    'value' => 'initialValue2',
3875
                    'languageCode' => 'eng-GB',
3876
                ]
3877
            ),
3878
        ];
3879
3880
        $fieldDefinitions = [
3881
            new FieldDefinition(
3882
                [
3883
                    'id' => 'fieldDefinitionId1',
3884
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
3885
                    'isTranslatable' => true,
3886
                    'identifier' => 'identifier1',
3887
                    'isRequired' => false,
3888
                    'defaultValue' => 'defaultValue1',
3889
                ]
3890
            ),
3891
            new FieldDefinition(
3892
                [
3893
                    'id' => 'fieldDefinitionId2',
3894
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
3895
                    'isTranslatable' => false,
3896
                    'identifier' => 'identifier2',
3897
                    'isRequired' => false,
3898
                    'defaultValue' => 'defaultValue2',
3899
                ]
3900
            ),
3901
        ];
3902
3903
        $this->assertForTestUpdateContentNonRedundantFieldSet(
3904
            $initialLanguageCode,
3905
            $structFields,
3906
            $spiFields,
3907
            $existingFields,
3908
            $fieldDefinitions
3909
        );
3910
    }
3911
3912
    public function providerForTestUpdateContentNonRedundantFieldSet4()
3913
    {
3914
        $spiFields0 = [
3915
            new SPIField(
3916
                [
3917
                    'id' => null,
3918
                    'fieldDefinitionId' => 'fieldDefinitionId1',
3919
                    'type' => 'fieldTypeIdentifier',
3920
                    'value' => 'newValue1',
3921
                    'languageCode' => 'eng-US',
3922
                    'versionNo' => 7,
3923
                ]
3924
            ),
3925
        ];
3926
        $spiFields1 = [
3927
            new SPIField(
3928
                [
3929
                    'id' => 100,
3930
                    'fieldDefinitionId' => 'fieldDefinitionId1',
3931
                    'type' => 'fieldTypeIdentifier',
3932
                    'value' => self::EMPTY_FIELD_VALUE,
3933
                    'languageCode' => 'eng-GB',
3934
                    'versionNo' => 7,
3935
                ]
3936
            ),
3937
            new SPIField(
3938
                [
3939
                    'id' => null,
3940
                    'fieldDefinitionId' => 'fieldDefinitionId1',
3941
                    'type' => 'fieldTypeIdentifier',
3942
                    'value' => 'newValue1',
3943
                    'languageCode' => 'eng-US',
3944
                    'versionNo' => 7,
3945
                ]
3946
            ),
3947
        ];
3948
        $spiFields2 = [
3949
            new SPIField(
3950
                [
3951
                    'id' => 100,
3952
                    'fieldDefinitionId' => 'fieldDefinitionId1',
3953
                    'type' => 'fieldTypeIdentifier',
3954
                    'value' => self::EMPTY_FIELD_VALUE,
3955
                    'languageCode' => 'eng-GB',
3956
                    'versionNo' => 7,
3957
                ]
3958
            ),
3959
        ];
3960
3961
        return [
3962
            // 0. New translation with empty field by default
3963
            [
3964
                'eng-US',
3965
                [
3966
                    new Field(
3967
                        [
3968
                            'fieldDefIdentifier' => 'identifier1',
3969
                            'value' => 'newValue1',
3970
                            'languageCode' => 'eng-US',
3971
                        ]
3972
                    ),
3973
                ],
3974
                $spiFields0,
3975
            ],
3976
            // 1. New translation with empty field by default, without language set
3977
            [
3978
                'eng-US',
3979
                [
3980
                    new Field(
3981
                        [
3982
                            'fieldDefIdentifier' => 'identifier1',
3983
                            'value' => 'newValue1',
3984
                            'languageCode' => null,
3985
                        ]
3986
                    ),
3987
                ],
3988
                $spiFields0,
3989
            ],
3990
            // 2. New translation with empty field given
3991
            [
3992
                'eng-US',
3993
                [
3994
                    new Field(
3995
                        [
3996
                            'fieldDefIdentifier' => 'identifier1',
3997
                            'value' => 'newValue1',
3998
                            'languageCode' => 'eng-US',
3999
                        ]
4000
                    ),
4001
                    new Field(
4002
                        [
4003
                            'fieldDefIdentifier' => 'identifier2',
4004
                            'value' => self::EMPTY_FIELD_VALUE,
4005
                            'languageCode' => 'eng-US',
4006
                        ]
4007
                    ),
4008
                ],
4009
                $spiFields0,
4010
            ],
4011
            // 3. New translation with empty field given, without language set
4012
            [
4013
                'eng-US',
4014
                [
4015
                    new Field(
4016
                        [
4017
                            'fieldDefIdentifier' => 'identifier1',
4018
                            'value' => 'newValue1',
4019
                            'languageCode' => null,
4020
                        ]
4021
                    ),
4022
                    new Field(
4023
                        [
4024
                            'fieldDefIdentifier' => 'identifier2',
4025
                            'value' => self::EMPTY_FIELD_VALUE,
4026
                            'languageCode' => null,
4027
                        ]
4028
                    ),
4029
                ],
4030
                $spiFields0,
4031
            ],
4032
            // 4. Updating existing language with empty value
4033
            [
4034
                'eng-US',
4035
                [
4036
                    new Field(
4037
                        [
4038
                            'fieldDefIdentifier' => 'identifier1',
4039
                            'value' => 'newValue1',
4040
                            'languageCode' => 'eng-US',
4041
                        ]
4042
                    ),
4043
                    new Field(
4044
                        [
4045
                            'fieldDefIdentifier' => 'identifier1',
4046
                            'value' => self::EMPTY_FIELD_VALUE,
4047
                            'languageCode' => 'eng-GB',
4048
                        ]
4049
                    ),
4050
                ],
4051
                $spiFields1,
4052
            ],
4053
            // 5. Updating existing language with empty value, without language set
4054
            [
4055
                'eng-US',
4056
                [
4057
                    new Field(
4058
                        [
4059
                            'fieldDefIdentifier' => 'identifier1',
4060
                            'value' => 'newValue1',
4061
                            'languageCode' => null,
4062
                        ]
4063
                    ),
4064
                    new Field(
4065
                        [
4066
                            'fieldDefIdentifier' => 'identifier1',
4067
                            'value' => self::EMPTY_FIELD_VALUE,
4068
                            'languageCode' => 'eng-GB',
4069
                        ]
4070
                    ),
4071
                ],
4072
                $spiFields1,
4073
            ],
4074
            // 6. Updating existing language with empty value and adding new language with empty value
4075
            [
4076
                'eng-US',
4077
                [
4078
                    new Field(
4079
                        [
4080
                            'fieldDefIdentifier' => 'identifier1',
4081
                            'value' => self::EMPTY_FIELD_VALUE,
4082
                            'languageCode' => 'eng-US',
4083
                        ]
4084
                    ),
4085
                    new Field(
4086
                        [
4087
                            'fieldDefIdentifier' => 'identifier1',
4088
                            'value' => self::EMPTY_FIELD_VALUE,
4089
                            'languageCode' => 'eng-GB',
4090
                        ]
4091
                    ),
4092
                ],
4093
                $spiFields2,
4094
            ],
4095
            // 7. Updating existing language with empty value and adding new language with empty value,
4096
            // without language set
4097
            [
4098
                'eng-US',
4099
                [
4100
                    new Field(
4101
                        [
4102
                            'fieldDefIdentifier' => 'identifier1',
4103
                            'value' => self::EMPTY_FIELD_VALUE,
4104
                            'languageCode' => null,
4105
                        ]
4106
                    ),
4107
                    new Field(
4108
                        [
4109
                            'fieldDefIdentifier' => 'identifier1',
4110
                            'value' => self::EMPTY_FIELD_VALUE,
4111
                            'languageCode' => 'eng-GB',
4112
                        ]
4113
                    ),
4114
                ],
4115
                $spiFields2,
4116
            ],
4117
            // 8. Adding new language with no fields given
4118
            [
4119
                'eng-US',
4120
                [],
4121
                [],
4122
            ],
4123
            // 9. Adding new language with fields
4124
            [
4125
                'eng-US',
4126
                [
4127
                    new Field(
4128
                        [
4129
                            'fieldDefIdentifier' => 'identifier1',
4130
                            'value' => self::EMPTY_FIELD_VALUE,
4131
                            'languageCode' => 'eng-US',
4132
                        ]
4133
                    ),
4134
                ],
4135
                [],
4136
            ],
4137
            // 10. Adding new language with fields, without language set
4138
            [
4139
                'eng-US',
4140
                [
4141
                    new Field(
4142
                        [
4143
                            'fieldDefIdentifier' => 'identifier1',
4144
                            'value' => self::EMPTY_FIELD_VALUE,
4145
                            'languageCode' => null,
4146
                        ]
4147
                    ),
4148
                ],
4149
                [],
4150
            ],
4151
        ];
4152
    }
4153
4154
    /**
4155
     * Test for the updateContent() method.
4156
     *
4157
     * Testing with empty values.
4158
     *
4159
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForUpdate
4160
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForUpdate
4161
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContent
4162
     * @dataProvider providerForTestUpdateContentNonRedundantFieldSet4
4163
     */
4164
    public function testUpdateContentNonRedundantFieldSet4($initialLanguageCode, $structFields, $spiFields)
4165
    {
4166
        $existingFields = [
4167
            new Field(
4168
                [
4169
                    'id' => '100',
4170
                    'fieldDefIdentifier' => 'identifier1',
4171
                    'value' => 'initialValue1',
4172
                    'languageCode' => 'eng-GB',
4173
                ]
4174
            ),
4175
            new Field(
4176
                [
4177
                    'id' => '101',
4178
                    'fieldDefIdentifier' => 'identifier2',
4179
                    'value' => 'initialValue2',
4180
                    'languageCode' => 'eng-GB',
4181
                ]
4182
            ),
4183
        ];
4184
4185
        $fieldDefinitions = [
4186
            new FieldDefinition(
4187
                [
4188
                    'id' => 'fieldDefinitionId1',
4189
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
4190
                    'isTranslatable' => true,
4191
                    'identifier' => 'identifier1',
4192
                    'isRequired' => false,
4193
                    'defaultValue' => self::EMPTY_FIELD_VALUE,
4194
                ]
4195
            ),
4196
            new FieldDefinition(
4197
                [
4198
                    'id' => 'fieldDefinitionId2',
4199
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
4200
                    'isTranslatable' => true,
4201
                    'identifier' => 'identifier2',
4202
                    'isRequired' => false,
4203
                    'defaultValue' => self::EMPTY_FIELD_VALUE,
4204
                ]
4205
            ),
4206
        ];
4207
4208
        $this->assertForTestUpdateContentNonRedundantFieldSet(
4209
            $initialLanguageCode,
4210
            $structFields,
4211
            $spiFields,
4212
            $existingFields,
4213
            $fieldDefinitions
4214
        );
4215
    }
4216
4217
    /**
4218
     * @todo add first field empty
4219
     *
4220
     * @return array
4221
     */
4222
    public function providerForTestUpdateContentNonRedundantFieldSetComplex()
4223
    {
4224
        $spiFields0 = [
4225
            new SPIField(
4226
                [
4227
                    'id' => 100,
4228
                    'fieldDefinitionId' => 'fieldDefinitionId1',
4229
                    'type' => 'fieldTypeIdentifier',
4230
                    'value' => 'newValue1-eng-GB',
4231
                    'languageCode' => 'eng-GB',
4232
                    'versionNo' => 7,
4233
                ]
4234
            ),
4235
            new SPIField(
4236
                [
4237
                    'id' => null,
4238
                    'fieldDefinitionId' => 'fieldDefinitionId4',
4239
                    'type' => 'fieldTypeIdentifier',
4240
                    'value' => 'newValue4',
4241
                    'languageCode' => 'eng-US',
4242
                    'versionNo' => 7,
4243
                ]
4244
            ),
4245
        ];
4246
        $spiFields1 = [
4247
            new SPIField(
4248
                [
4249
                    'id' => 100,
4250
                    'fieldDefinitionId' => 'fieldDefinitionId1',
4251
                    'type' => 'fieldTypeIdentifier',
4252
                    'value' => 'newValue1-eng-GB',
4253
                    'languageCode' => 'eng-GB',
4254
                    'versionNo' => 7,
4255
                ]
4256
            ),
4257
            new SPIField(
4258
                [
4259
                    'id' => null,
4260
                    'fieldDefinitionId' => 'fieldDefinitionId2',
4261
                    'type' => 'fieldTypeIdentifier',
4262
                    'value' => 'newValue2',
4263
                    'languageCode' => 'eng-US',
4264
                    'versionNo' => 7,
4265
                ]
4266
            ),
4267
            new SPIField(
4268
                [
4269
                    'id' => null,
4270
                    'fieldDefinitionId' => 'fieldDefinitionId4',
4271
                    'type' => 'fieldTypeIdentifier',
4272
                    'value' => 'defaultValue4',
4273
                    'languageCode' => 'eng-US',
4274
                    'versionNo' => 7,
4275
                ]
4276
            ),
4277
        ];
4278
        $spiFields2 = [
4279
            new SPIField(
4280
                [
4281
                    'id' => 100,
4282
                    'fieldDefinitionId' => 'fieldDefinitionId1',
4283
                    'type' => 'fieldTypeIdentifier',
4284
                    'value' => 'newValue1-eng-GB',
4285
                    'languageCode' => 'eng-GB',
4286
                    'versionNo' => 7,
4287
                ]
4288
            ),
4289
            new SPIField(
4290
                [
4291
                    'id' => null,
4292
                    'fieldDefinitionId' => 'fieldDefinitionId2',
4293
                    'type' => 'fieldTypeIdentifier',
4294
                    'value' => 'newValue2',
4295
                    'languageCode' => 'eng-US',
4296
                    'versionNo' => 7,
4297
                ]
4298
            ),
4299
            new SPIField(
4300
                [
4301
                    'id' => null,
4302
                    'fieldDefinitionId' => 'fieldDefinitionId4',
4303
                    'type' => 'fieldTypeIdentifier',
4304
                    'value' => 'defaultValue4',
4305
                    'languageCode' => 'ger-DE',
4306
                    'versionNo' => 7,
4307
                ]
4308
            ),
4309
            new SPIField(
4310
                [
4311
                    'id' => null,
4312
                    'fieldDefinitionId' => 'fieldDefinitionId4',
4313
                    'type' => 'fieldTypeIdentifier',
4314
                    'value' => 'defaultValue4',
4315
                    'languageCode' => 'eng-US',
4316
                    'versionNo' => 7,
4317
                ]
4318
            ),
4319
        ];
4320
4321
        return [
4322
            // 0. Add new language and update existing
4323
            [
4324
                'eng-US',
4325
                [
4326
                    new Field(
4327
                        [
4328
                            'fieldDefIdentifier' => 'identifier4',
4329
                            'value' => 'newValue4',
4330
                            'languageCode' => 'eng-US',
4331
                        ]
4332
                    ),
4333
                    new Field(
4334
                        [
4335
                            'fieldDefIdentifier' => 'identifier1',
4336
                            'value' => 'newValue1-eng-GB',
4337
                            'languageCode' => 'eng-GB',
4338
                        ]
4339
                    ),
4340
                ],
4341
                $spiFields0,
4342
            ],
4343
            // 1. Add new language and update existing, without language set
4344
            [
4345
                'eng-US',
4346
                [
4347
                    new Field(
4348
                        [
4349
                            'fieldDefIdentifier' => 'identifier4',
4350
                            'value' => 'newValue4',
4351
                            'languageCode' => null,
4352
                        ]
4353
                    ),
4354
                    new Field(
4355
                        [
4356
                            'fieldDefIdentifier' => 'identifier1',
4357
                            'value' => 'newValue1-eng-GB',
4358
                            'languageCode' => 'eng-GB',
4359
                        ]
4360
                    ),
4361
                ],
4362
                $spiFields0,
4363
            ],
4364
            // 2. Add new language and update existing variant
4365
            [
4366
                'eng-US',
4367
                [
4368
                    new Field(
4369
                        [
4370
                            'fieldDefIdentifier' => 'identifier2',
4371
                            'value' => 'newValue2',
4372
                            'languageCode' => 'eng-US',
4373
                        ]
4374
                    ),
4375
                    new Field(
4376
                        [
4377
                            'fieldDefIdentifier' => 'identifier1',
4378
                            'value' => 'newValue1-eng-GB',
4379
                            'languageCode' => 'eng-GB',
4380
                        ]
4381
                    ),
4382
                ],
4383
                $spiFields1,
4384
            ],
4385
            // 3. Add new language and update existing variant, without language set
4386
            [
4387
                'eng-US',
4388
                [
4389
                    new Field(
4390
                        [
4391
                            'fieldDefIdentifier' => 'identifier2',
4392
                            'value' => 'newValue2',
4393
                            'languageCode' => null,
4394
                        ]
4395
                    ),
4396
                    new Field(
4397
                        [
4398
                            'fieldDefIdentifier' => 'identifier1',
4399
                            'value' => 'newValue1-eng-GB',
4400
                            'languageCode' => 'eng-GB',
4401
                        ]
4402
                    ),
4403
                ],
4404
                $spiFields1,
4405
            ],
4406
            // 4. Update with multiple languages
4407
            [
4408
                'ger-DE',
4409
                [
4410
                    new Field(
4411
                        [
4412
                            'fieldDefIdentifier' => 'identifier2',
4413
                            'value' => 'newValue2',
4414
                            'languageCode' => 'eng-US',
4415
                        ]
4416
                    ),
4417
                    new Field(
4418
                        [
4419
                            'fieldDefIdentifier' => 'identifier1',
4420
                            'value' => 'newValue1-eng-GB',
4421
                            'languageCode' => 'eng-GB',
4422
                        ]
4423
                    ),
4424
                ],
4425
                $spiFields2,
4426
            ],
4427
            // 5. Update with multiple languages without language set
4428
            [
4429
                'ger-DE',
4430
                [
4431
                    new Field(
4432
                        [
4433
                            'fieldDefIdentifier' => 'identifier2',
4434
                            'value' => 'newValue2',
4435
                            'languageCode' => 'eng-US',
4436
                        ]
4437
                    ),
4438
                    new Field(
4439
                        [
4440
                            'fieldDefIdentifier' => 'identifier1',
4441
                            'value' => 'newValue1-eng-GB',
4442
                            'languageCode' => null,
4443
                        ]
4444
                    ),
4445
                ],
4446
                $spiFields2,
4447
            ],
4448
        ];
4449
    }
4450
4451
    protected function fixturesForTestUpdateContentNonRedundantFieldSetComplex()
4452
    {
4453
        $existingFields = [
4454
            new Field(
4455
                [
4456
                    'id' => '100',
4457
                    'fieldDefIdentifier' => 'identifier1',
4458
                    'value' => 'initialValue1',
4459
                    'languageCode' => 'eng-GB',
4460
                ]
4461
            ),
4462
            new Field(
4463
                [
4464
                    'id' => '101',
4465
                    'fieldDefIdentifier' => 'identifier2',
4466
                    'value' => 'initialValue2',
4467
                    'languageCode' => 'eng-GB',
4468
                ]
4469
            ),
4470
            new Field(
4471
                [
4472
                    'id' => '102',
4473
                    'fieldDefIdentifier' => 'identifier3',
4474
                    'value' => 'initialValue3',
4475
                    'languageCode' => 'eng-GB',
4476
                ]
4477
            ),
4478
            new Field(
4479
                [
4480
                    'id' => '103',
4481
                    'fieldDefIdentifier' => 'identifier4',
4482
                    'value' => 'initialValue4',
4483
                    'languageCode' => 'eng-GB',
4484
                ]
4485
            ),
4486
        ];
4487
4488
        $fieldDefinitions = [
4489
            new FieldDefinition(
4490
                [
4491
                    'id' => 'fieldDefinitionId1',
4492
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
4493
                    'isTranslatable' => false,
4494
                    'identifier' => 'identifier1',
4495
                    'isRequired' => false,
4496
                    'defaultValue' => self::EMPTY_FIELD_VALUE,
4497
                ]
4498
            ),
4499
            new FieldDefinition(
4500
                [
4501
                    'id' => 'fieldDefinitionId2',
4502
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
4503
                    'isTranslatable' => true,
4504
                    'identifier' => 'identifier2',
4505
                    'isRequired' => false,
4506
                    'defaultValue' => self::EMPTY_FIELD_VALUE,
4507
                ]
4508
            ),
4509
            new FieldDefinition(
4510
                [
4511
                    'id' => 'fieldDefinitionId3',
4512
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
4513
                    'isTranslatable' => false,
4514
                    'identifier' => 'identifier3',
4515
                    'isRequired' => false,
4516
                    'defaultValue' => 'defaultValue3',
4517
                ]
4518
            ),
4519
            new FieldDefinition(
4520
                [
4521
                    'id' => 'fieldDefinitionId4',
4522
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
4523
                    'isTranslatable' => true,
4524
                    'identifier' => 'identifier4',
4525
                    'isRequired' => false,
4526
                    'defaultValue' => 'defaultValue4',
4527
                ]
4528
            ),
4529
        ];
4530
4531
        return [$existingFields, $fieldDefinitions];
4532
    }
4533
4534
    /**
4535
     * Test for the updateContent() method.
4536
     *
4537
     * Testing more complex cases.
4538
     *
4539
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForUpdate
4540
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForUpdate
4541
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContent
4542
     * @dataProvider providerForTestUpdateContentNonRedundantFieldSetComplex
4543
     */
4544
    public function testUpdateContentNonRedundantFieldSetComplex($initialLanguageCode, $structFields, $spiFields)
4545
    {
4546
        list($existingFields, $fieldDefinitions) = $this->fixturesForTestUpdateContentNonRedundantFieldSetComplex();
4547
4548
        $this->assertForTestUpdateContentNonRedundantFieldSet(
4549
            $initialLanguageCode,
4550
            $structFields,
4551
            $spiFields,
4552
            $existingFields,
4553
            $fieldDefinitions
4554
        );
4555
    }
4556
4557 View Code Duplication
    public function providerForTestUpdateContentWithInvalidLanguage()
4558
    {
4559
        return [
4560
            [
4561
                'eng-GB',
4562
                [
4563
                    new Field(
4564
                        [
4565
                            'fieldDefIdentifier' => 'identifier',
4566
                            'value' => 'newValue',
4567
                            'languageCode' => 'Klingon',
4568
                        ]
4569
                    ),
4570
                ],
4571
            ],
4572
            [
4573
                'Klingon',
4574
                [
4575
                    new Field(
4576
                        [
4577
                            'fieldDefIdentifier' => 'identifier',
4578
                            'value' => 'newValue',
4579
                            'languageCode' => 'eng-GB',
4580
                        ]
4581
                    ),
4582
                ],
4583
            ],
4584
        ];
4585
    }
4586
4587
    /**
4588
     * Test for the updateContent() method.
4589
     *
4590
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForUpdate
4591
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContent
4592
     * @dataProvider providerForTestUpdateContentWithInvalidLanguage
4593
     */
4594
    public function testUpdateContentWithInvalidLanguage($initialLanguageCode, $structFields)
4595
    {
4596
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\NotFoundException::class);
4597
        $this->expectExceptionMessage('Could not find \'Language\' with identifier \'Klingon\'');
4598
4599
        $permissionResolverMock = $this->getPermissionResolverMock();
4600
        $mockedService = $this->getPartlyMockedContentService(['loadContent']);
4601
        /** @var \PHPUnit\Framework\MockObject\MockObject $languageHandlerMock */
4602
        $languageHandlerMock = $this->getPersistenceMock()->contentLanguageHandler();
4603
        $versionInfo = new VersionInfo(
4604
            [
4605
                'contentInfo' => new ContentInfo(
4606
                    [
4607
                        'id' => 42,
4608
                        'contentTypeId' => 24,
4609
                        'mainLanguageCode' => 'eng-GB',
4610
                    ]
4611
                ),
4612
                'versionNo' => 7,
4613
                'languageCodes' => ['eng-GB'],
4614
                'status' => VersionInfo::STATUS_DRAFT,
4615
            ]
4616
        );
4617
        $content = new Content(
4618
            [
4619
                'versionInfo' => $versionInfo,
4620
                'internalFields' => [],
4621
            ]
4622
        );
4623
4624
        $languageHandlerMock->expects($this->any())
4625
            ->method('loadByLanguageCode')
4626
            ->with($this->isType('string'))
4627
            ->will(
4628
                $this->returnCallback(
4629 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...
4630
                        if ($languageCode === 'Klingon') {
4631
                            throw new NotFoundException('Language', 'Klingon');
4632
                        }
4633
4634
                        return new Language(['id' => 4242]);
4635
                    }
4636
                )
4637
            );
4638
4639
        $mockedService->expects($this->once())
4640
            ->method('loadContent')
4641
            ->with(
4642
                $this->equalTo(42),
4643
                $this->equalTo(null),
4644
                $this->equalTo(7)
4645
            )->will(
4646
                $this->returnValue($content)
4647
            );
4648
4649
        $permissionResolverMock->expects($this->once())
4650
            ->method('canUser')
4651
            ->with(
4652
                $this->equalTo('content'),
4653
                $this->equalTo('edit'),
4654
                $this->equalTo($content),
4655
                $this->isType('array')
4656
            )->will($this->returnValue(true));
4657
4658
        $contentUpdateStruct = new ContentUpdateStruct(
4659
            [
4660
                'fields' => $structFields,
4661
                'initialLanguageCode' => $initialLanguageCode,
4662
            ]
4663
        );
4664
4665
        $mockedService->updateContent($content->versionInfo, $contentUpdateStruct);
4666
    }
4667
4668
    protected function assertForUpdateContentContentValidationException(
4669
        $initialLanguageCode,
4670
        $structFields,
4671
        $fieldDefinitions = []
4672
    ) {
4673
        $repositoryMock = $this->getRepositoryMock();
4674
        $permissionResolverMock = $this->getPermissionResolverMock();
4675
        $mockedService = $this->getPartlyMockedContentService(['loadContent']);
4676
        /** @var \PHPUnit\Framework\MockObject\MockObject $languageHandlerMock */
4677
        $languageHandlerMock = $this->getPersistenceMock()->contentLanguageHandler();
4678
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
4679
        $versionInfo = new VersionInfo(
4680
            [
4681
                'contentInfo' => new ContentInfo(
4682
                    [
4683
                        'id' => 42,
4684
                        'contentTypeId' => 24,
4685
                        'mainLanguageCode' => 'eng-GB',
4686
                    ]
4687
                ),
4688
                'versionNo' => 7,
4689
                'languageCodes' => ['eng-GB'],
4690
                'status' => VersionInfo::STATUS_DRAFT,
4691
            ]
4692
        );
4693
        $content = new Content(
4694
            [
4695
                'versionInfo' => $versionInfo,
4696
                'internalFields' => [],
4697
            ]
4698
        );
4699
        $contentType = new ContentType(['fieldDefinitions' => $fieldDefinitions]);
4700
4701
        $languageHandlerMock->expects($this->any())
4702
            ->method('loadByLanguageCode')
4703
            ->with($this->isType('string'))
4704
            ->will(
4705
                $this->returnCallback(
4706 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...
4707
                        if ($languageCode === 'Klingon') {
4708
                            throw new NotFoundException('Language', 'Klingon');
4709
                        }
4710
4711
                        return new Language(['id' => 4242]);
4712
                    }
4713
                )
4714
            );
4715
4716
        $mockedService->expects($this->once())
4717
            ->method('loadContent')
4718
            ->with(
4719
                $this->equalTo(42),
4720
                $this->equalTo(null),
4721
                $this->equalTo(7)
4722
            )->will(
4723
                $this->returnValue($content)
4724
            );
4725
4726
        $permissionResolverMock->expects($this->once())
4727
            ->method('canUser')
4728
            ->with(
4729
                $this->equalTo('content'),
4730
                $this->equalTo('edit'),
4731
                $this->equalTo($content),
4732
                $this->isType('array')
4733
            )->will($this->returnValue(true));
4734
4735
        $contentTypeServiceMock->expects($this->once())
4736
            ->method('loadContentType')
4737
            ->with($this->equalTo(24))
4738
            ->will($this->returnValue($contentType));
4739
4740
        $repositoryMock->expects($this->once())
4741
            ->method('getContentTypeService')
4742
            ->will($this->returnValue($contentTypeServiceMock));
4743
4744
        $contentUpdateStruct = new ContentUpdateStruct(
4745
            [
4746
                'fields' => $structFields,
4747
                'initialLanguageCode' => $initialLanguageCode,
4748
            ]
4749
        );
4750
4751
        $mockedService->updateContent($content->versionInfo, $contentUpdateStruct);
4752
    }
4753
4754 View Code Duplication
    public function providerForTestUpdateContentThrowsContentValidationExceptionFieldDefinition()
4755
    {
4756
        return [
4757
            [
4758
                'eng-GB',
4759
                [
4760
                    new Field(
4761
                        [
4762
                            'fieldDefIdentifier' => 'identifier',
4763
                            'value' => 'newValue',
4764
                            'languageCode' => 'eng-GB',
4765
                        ]
4766
                    ),
4767
                ],
4768
            ],
4769
        ];
4770
    }
4771
4772
    /**
4773
     * Test for the updateContent() method.
4774
     *
4775
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForUpdate
4776
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForUpdate
4777
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContent
4778
     * @dataProvider providerForTestUpdateContentThrowsContentValidationExceptionFieldDefinition
4779
     */
4780
    public function testUpdateContentThrowsContentValidationExceptionFieldDefinition($initialLanguageCode, $structFields)
4781
    {
4782
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\ContentValidationException::class);
4783
        $this->expectExceptionMessage('Field definition \'identifier\' does not exist in given ContentType');
4784
4785
        $this->assertForUpdateContentContentValidationException(
4786
            $initialLanguageCode,
4787
            $structFields,
4788
            []
4789
        );
4790
    }
4791
4792 View Code Duplication
    public function providerForTestUpdateContentThrowsContentValidationExceptionTranslation()
4793
    {
4794
        return [
4795
            [
4796
                'eng-US',
4797
                [
4798
                    new Field(
4799
                        [
4800
                            'fieldDefIdentifier' => 'identifier',
4801
                            'value' => 'newValue',
4802
                            'languageCode' => 'eng-US',
4803
                        ]
4804
                    ),
4805
                ],
4806
            ],
4807
        ];
4808
    }
4809
4810
    /**
4811
     * Test for the updateContent() method.
4812
     *
4813
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForUpdate
4814
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForUpdate
4815
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContent
4816
     * @dataProvider providerForTestUpdateContentThrowsContentValidationExceptionTranslation
4817
     */
4818 View Code Duplication
    public function testUpdateContentThrowsContentValidationExceptionTranslation($initialLanguageCode, $structFields)
4819
    {
4820
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\ContentValidationException::class);
4821
        $this->expectExceptionMessage('A value is set for non translatable field definition \'identifier\' with language \'eng-US\'');
4822
4823
        $fieldDefinitions = [
4824
            new FieldDefinition(
4825
                [
4826
                    'id' => 'fieldDefinitionId1',
4827
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
4828
                    'isTranslatable' => false,
4829
                    'identifier' => 'identifier',
4830
                    'isRequired' => false,
4831
                    'defaultValue' => self::EMPTY_FIELD_VALUE,
4832
                ]
4833
            ),
4834
        ];
4835
4836
        $this->assertForUpdateContentContentValidationException(
4837
            $initialLanguageCode,
4838
            $structFields,
4839
            $fieldDefinitions
4840
        );
4841
    }
4842
4843
    public function assertForTestUpdateContentRequiredField(
4844
        $initialLanguageCode,
4845
        $structFields,
4846
        $existingFields,
4847
        $fieldDefinitions
4848
    ) {
4849
        $repositoryMock = $this->getRepositoryMock();
4850
        $permissionResolver = $this->getPermissionResolverMock();
4851
        $mockedService = $this->getPartlyMockedContentService(['loadContent']);
4852
        /** @var \PHPUnit\Framework\MockObject\MockObject $languageHandlerMock */
4853
        $languageHandlerMock = $this->getPersistenceMock()->contentLanguageHandler();
4854
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
4855
        $fieldTypeMock = $this->createMock(SPIFieldType::class);
4856
        $existingLanguageCodes = array_map(
4857
            function (Field $field) {
4858
                return $field->languageCode;
4859
            },
4860
            $existingFields
4861
        );
4862
        $versionInfo = new VersionInfo(
4863
            [
4864
                'contentInfo' => new ContentInfo(
4865
                    [
4866
                        'id' => 42,
4867
                        'contentTypeId' => 24,
4868
                        'mainLanguageCode' => 'eng-GB',
4869
                    ]
4870
                ),
4871
                'versionNo' => 7,
4872
                'languageCodes' => $existingLanguageCodes,
4873
                'status' => VersionInfo::STATUS_DRAFT,
4874
            ]
4875
        );
4876
        $content = new Content(
4877
            [
4878
                'versionInfo' => $versionInfo,
4879
                'internalFields' => $existingFields,
4880
            ]
4881
        );
4882
        $contentType = new ContentType(['fieldDefinitions' => $fieldDefinitions]);
4883
4884
        $languageHandlerMock->expects($this->any())
4885
            ->method('loadByLanguageCode')
4886
            ->with($this->isType('string'))
4887
            ->will(
4888
                $this->returnCallback(
4889
                    function () {
4890
                        return new Language(['id' => 4242]);
4891
                    }
4892
                )
4893
            );
4894
4895
        $mockedService->expects($this->once())
4896
            ->method('loadContent')
4897
            ->with(
4898
                $this->equalTo(42),
4899
                $this->equalTo(null),
4900
                $this->equalTo(7)
4901
            )->will(
4902
                $this->returnValue($content)
4903
            );
4904
4905
        $permissionResolver->expects($this->once())
4906
            ->method('canUser')
4907
            ->with(
4908
                $this->equalTo('content'),
4909
                $this->equalTo('edit'),
4910
                $this->equalTo($content),
4911
                $this->isType('array')
4912
            )->will($this->returnValue(true));
4913
4914
        $contentTypeServiceMock->expects($this->once())
4915
            ->method('loadContentType')
4916
            ->with($this->equalTo(24))
4917
            ->will($this->returnValue($contentType));
4918
4919
        $repositoryMock->expects($this->once())
4920
            ->method('getContentTypeService')
4921
            ->will($this->returnValue($contentTypeServiceMock));
4922
4923
        $fieldTypeMock->expects($this->any())
4924
            ->method('acceptValue')
4925
            ->will(
4926
                $this->returnCallback(
4927
                    function ($valueString) {
4928
                        return new ValueStub($valueString);
4929
                    }
4930
                )
4931
            );
4932
4933
        $emptyValue = self::EMPTY_FIELD_VALUE;
4934
        $fieldTypeMock->expects($this->any())
4935
            ->method('isEmptyValue')
4936
            ->will(
4937
                $this->returnCallback(
4938
                    function (ValueStub $value) use ($emptyValue) {
4939
                        return $emptyValue === (string)$value;
4940
                    }
4941
                )
4942
            );
4943
4944
        $fieldTypeMock->expects($this->any())
4945
            ->method('validate')
4946
            ->with(
4947
                $this->isInstanceOf(APIFieldDefinition::class),
4948
                $this->isInstanceOf(Value::class)
4949
            );
4950
4951
        $this->getFieldTypeRegistryMock()->expects($this->any())
4952
            ->method('getFieldType')
4953
            ->will($this->returnValue($fieldTypeMock));
4954
4955
        $contentUpdateStruct = new ContentUpdateStruct(
4956
            [
4957
                'fields' => $structFields,
4958
                'initialLanguageCode' => $initialLanguageCode,
4959
            ]
4960
        );
4961
4962
        return [$content->versionInfo, $contentUpdateStruct];
4963
    }
4964
4965 View Code Duplication
    public function providerForTestUpdateContentRequiredField()
4966
    {
4967
        return [
4968
            [
4969
                'eng-US',
4970
                [
4971
                    new Field(
4972
                        [
4973
                            'fieldDefIdentifier' => 'identifier',
4974
                            'value' => self::EMPTY_FIELD_VALUE,
4975
                            'languageCode' => null,
4976
                        ]
4977
                    ),
4978
                ],
4979
                'identifier',
4980
                'eng-US',
4981
            ],
4982
        ];
4983
    }
4984
4985
    /**
4986
     * Test for the updateContent() method.
4987
     *
4988
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForUpdate
4989
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForUpdate
4990
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContent
4991
     * @dataProvider providerForTestUpdateContentRequiredField
4992
     */
4993
    public function testUpdateContentRequiredField(
4994
        $initialLanguageCode,
4995
        $structFields,
4996
        $identifier,
4997
        $languageCode
4998
    ) {
4999
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\ContentFieldValidationException::class);
5000
5001
        $existingFields = [
5002
            new Field(
5003
                [
5004
                    'id' => '100',
5005
                    'fieldDefIdentifier' => 'identifier',
5006
                    'value' => 'initialValue',
5007
                    'languageCode' => 'eng-GB',
5008
                ]
5009
            ),
5010
        ];
5011
        $fieldDefinitions = [
5012
            new FieldDefinition(
5013
                [
5014
                    'id' => 'fieldDefinitionId',
5015
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
5016
                    'isTranslatable' => true,
5017
                    'identifier' => 'identifier',
5018
                    'isRequired' => true,
5019
                    'defaultValue' => 'defaultValue',
5020
                ]
5021
            ),
5022
        ];
5023
        list($versionInfo, $contentUpdateStruct) =
5024
            $this->assertForTestUpdateContentRequiredField(
5025
                $initialLanguageCode,
5026
                $structFields,
5027
                $existingFields,
5028
                $fieldDefinitions
5029
            );
5030
5031
        try {
5032
            $this->partlyMockedContentService->updateContent($versionInfo, $contentUpdateStruct);
5033
        } catch (ContentValidationException $e) {
5034
            $this->assertEquals(
5035
                "Value for required field definition '{$identifier}' with language '{$languageCode}' is empty",
5036
                $e->getMessage()
5037
            );
5038
5039
            throw $e;
5040
        }
5041
    }
5042
5043
    public function assertForTestUpdateContentThrowsContentFieldValidationException(
5044
        $initialLanguageCode,
5045
        $structFields,
5046
        $existingFields,
5047
        $fieldDefinitions
5048
    ) {
5049
        $repositoryMock = $this->getRepositoryMock();
5050
        $permissionResolverMock = $this->getPermissionResolverMock();
5051
        $mockedService = $this->getPartlyMockedContentService(['loadContent']);
5052
        /** @var \PHPUnit\Framework\MockObject\MockObject $languageHandlerMock */
5053
        $languageHandlerMock = $this->getPersistenceMock()->contentLanguageHandler();
5054
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
5055
        $fieldTypeMock = $this->createMock(SPIFieldType::class);
5056
        $existingLanguageCodes = array_map(
5057
            function (Field $field) {
5058
                return $field->languageCode;
5059
            },
5060
            $existingFields
5061
        );
5062
        $languageCodes = $this->determineLanguageCodesForUpdate(
5063
            $initialLanguageCode,
5064
            $structFields,
5065
            $existingLanguageCodes
5066
        );
5067
        $versionInfo = new VersionInfo(
5068
            [
5069
                'contentInfo' => new ContentInfo(
5070
                    [
5071
                        'id' => 42,
5072
                        'contentTypeId' => 24,
5073
                        'mainLanguageCode' => 'eng-GB',
5074
                    ]
5075
                ),
5076
                'versionNo' => 7,
5077
                'languageCodes' => $existingLanguageCodes,
5078
                'status' => VersionInfo::STATUS_DRAFT,
5079
            ]
5080
        );
5081
        $content = new Content(
5082
            [
5083
                'versionInfo' => $versionInfo,
5084
                'internalFields' => $existingFields,
5085
            ]
5086
        );
5087
        $contentType = new ContentType(['fieldDefinitions' => $fieldDefinitions]);
5088
5089
        $languageHandlerMock->expects($this->any())
5090
            ->method('loadByLanguageCode')
5091
            ->with($this->isType('string'))
5092
            ->will(
5093
                $this->returnCallback(
5094
                    function () {
5095
                        return new Language(['id' => 4242]);
5096
                    }
5097
                )
5098
            );
5099
5100
        $mockedService->expects($this->once())
5101
            ->method('loadContent')
5102
            ->with(
5103
                $this->equalTo(42),
5104
                $this->equalTo(null),
5105
                $this->equalTo(7)
5106
            )->will(
5107
                $this->returnValue($content)
5108
            );
5109
5110
        $permissionResolverMock->expects($this->once())
5111
            ->method('canUser')
5112
            ->with(
5113
                $this->equalTo('content'),
5114
                $this->equalTo('edit'),
5115
                $this->equalTo($content),
5116
                $this->isType('array')
5117
            )->will($this->returnValue(true));
5118
5119
        $contentTypeServiceMock->expects($this->once())
5120
            ->method('loadContentType')
5121
            ->with($this->equalTo(24))
5122
            ->will($this->returnValue($contentType));
5123
5124
        $repositoryMock->expects($this->once())
5125
            ->method('getContentTypeService')
5126
            ->will($this->returnValue($contentTypeServiceMock));
5127
5128
        $fieldValues = $this->determineValuesForUpdate(
5129
            $initialLanguageCode,
5130
            $structFields,
5131
            $content,
5132
            $fieldDefinitions,
5133
            $languageCodes
5134
        );
5135
        $allFieldErrors = [];
5136
        $emptyValue = self::EMPTY_FIELD_VALUE;
5137
5138
        $fieldTypeMock->expects($this->exactly(count($fieldValues) * count($languageCodes)))
5139
            ->method('acceptValue')
5140
            ->will(
5141
                $this->returnCallback(
5142
                    function ($valueString) {
5143
                        return new ValueStub($valueString);
5144
                    }
5145
                )
5146
            );
5147
5148
        $fieldTypeMock->expects($this->exactly(count($fieldValues) * count($languageCodes)))
5149
            ->method('isEmptyValue')
5150
            ->will(
5151
                $this->returnCallback(
5152
                    function (ValueStub $value) use ($emptyValue) {
5153
                        return $emptyValue === (string)$value;
5154
                    }
5155
                )
5156
            );
5157
5158
        $fieldTypeMock
5159
            ->expects($this->any())
5160
            ->method('validate')
5161
            ->willReturnArgument(1);
5162
5163
        $this->getFieldTypeRegistryMock()->expects($this->any())
5164
            ->method('getFieldType')
5165
            ->will($this->returnValue($fieldTypeMock));
5166
5167
        $contentUpdateStruct = new ContentUpdateStruct(
5168
            [
5169
                'fields' => $structFields,
5170
                'initialLanguageCode' => $initialLanguageCode,
5171
            ]
5172
        );
5173
5174
        return [$content->versionInfo, $contentUpdateStruct, $allFieldErrors];
5175
    }
5176
5177
    public function providerForTestUpdateContentThrowsContentFieldValidationException()
5178
    {
5179
        $allFieldErrors = [
5180
            [
5181
                'fieldDefinitionId1' => [
5182
                    'eng-GB' => 'newValue1-eng-GB',
5183
                    'eng-US' => 'newValue1-eng-GB',
5184
                ],
5185
                'fieldDefinitionId2' => [
5186
                    'eng-GB' => 'initialValue2',
5187
                ],
5188
                'fieldDefinitionId3' => [
5189
                    'eng-GB' => 'initialValue3',
5190
                    'eng-US' => 'initialValue3',
5191
                ],
5192
                'fieldDefinitionId4' => [
5193
                    'eng-GB' => 'initialValue4',
5194
                    'eng-US' => 'newValue4',
5195
                ],
5196
            ],
5197
            [
5198
                'fieldDefinitionId1' => [
5199
                    'eng-GB' => 'newValue1-eng-GB',
5200
                    'eng-US' => 'newValue1-eng-GB',
5201
                ],
5202
                'fieldDefinitionId2' => [
5203
                    'eng-GB' => 'initialValue2',
5204
                ],
5205
                'fieldDefinitionId3' => [
5206
                    'eng-GB' => 'initialValue3',
5207
                    'eng-US' => 'initialValue3',
5208
                ],
5209
                'fieldDefinitionId4' => [
5210
                    'eng-GB' => 'initialValue4',
5211
                    'eng-US' => 'newValue4',
5212
                ],
5213
            ],
5214
            [
5215
                'fieldDefinitionId1' => [
5216
                    'eng-GB' => 'newValue1-eng-GB',
5217
                    'eng-US' => 'newValue1-eng-GB',
5218
                ],
5219
                'fieldDefinitionId2' => [
5220
                    'eng-GB' => 'initialValue2',
5221
                    'eng-US' => 'newValue2',
5222
                ],
5223
                'fieldDefinitionId3' => [
5224
                    'eng-GB' => 'initialValue3',
5225
                    'eng-US' => 'initialValue3',
5226
                ],
5227
                'fieldDefinitionId4' => [
5228
                    'eng-GB' => 'initialValue4',
5229
                    'eng-US' => 'defaultValue4',
5230
                ],
5231
            ],
5232
            [
5233
                'fieldDefinitionId1' => [
5234
                    'eng-GB' => 'newValue1-eng-GB',
5235
                    'eng-US' => 'newValue1-eng-GB',
5236
                ],
5237
                'fieldDefinitionId2' => [
5238
                    'eng-GB' => 'initialValue2',
5239
                    'eng-US' => 'newValue2',
5240
                ],
5241
                'fieldDefinitionId3' => [
5242
                    'eng-GB' => 'initialValue3',
5243
                    'eng-US' => 'initialValue3',
5244
                ],
5245
                'fieldDefinitionId4' => [
5246
                    'eng-GB' => 'initialValue4',
5247
                    'eng-US' => 'defaultValue4',
5248
                ],
5249
            ],
5250
            [
5251
                'fieldDefinitionId1' => [
5252
                    'eng-GB' => 'newValue1-eng-GB',
5253
                    'ger-DE' => 'newValue1-eng-GB',
5254
                    'eng-US' => 'newValue1-eng-GB',
5255
                ],
5256
                'fieldDefinitionId2' => [
5257
                    'eng-GB' => 'initialValue2',
5258
                    'eng-US' => 'newValue2',
5259
                ],
5260
                'fieldDefinitionId3' => [
5261
                    'eng-GB' => 'initialValue3',
5262
                    'ger-DE' => 'initialValue3',
5263
                    'eng-US' => 'initialValue3',
5264
                ],
5265
                'fieldDefinitionId4' => [
5266
                    'eng-GB' => 'initialValue4',
5267
                    'eng-US' => 'defaultValue4',
5268
                    'ger-DE' => 'defaultValue4',
5269
                ],
5270
            ],
5271
            [
5272
                'fieldDefinitionId1' => [
5273
                    'eng-US' => 'newValue1-eng-GB',
5274
                    'ger-DE' => 'newValue1-eng-GB',
5275
                ],
5276
                'fieldDefinitionId2' => [
5277
                    'eng-US' => 'newValue2',
5278
                ],
5279
                'fieldDefinitionId3' => [
5280
                    'ger-DE' => 'initialValue3',
5281
                    'eng-US' => 'initialValue3',
5282
                ],
5283
                'fieldDefinitionId4' => [
5284
                    'ger-DE' => 'defaultValue4',
5285
                    'eng-US' => 'defaultValue4',
5286
                ],
5287
            ],
5288
        ];
5289
5290
        $data = $this->providerForTestUpdateContentNonRedundantFieldSetComplex();
5291
        $count = count($data);
5292
        for ($i = 0; $i < $count; ++$i) {
5293
            $data[$i][] = $allFieldErrors[$i];
5294
        }
5295
5296
        return $data;
5297
    }
5298
5299
    /**
5300
     * Test for the updateContent() method.
5301
     *
5302
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForUpdate
5303
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForUpdate
5304
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContent
5305
     * @dataProvider providerForTestUpdateContentThrowsContentFieldValidationException
5306
     */
5307 View Code Duplication
    public function testUpdateContentThrowsContentFieldValidationException($initialLanguageCode, $structFields, $spiField, $allFieldErrors)
5308
    {
5309
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\ContentFieldValidationException::class);
5310
        $this->expectExceptionMessage('Content fields did not validate');
5311
5312
        list($existingFields, $fieldDefinitions) = $this->fixturesForTestUpdateContentNonRedundantFieldSetComplex();
5313
        list($versionInfo, $contentUpdateStruct) =
5314
            $this->assertForTestUpdateContentThrowsContentFieldValidationException(
5315
                $initialLanguageCode,
5316
                $structFields,
5317
                $existingFields,
5318
                $fieldDefinitions
5319
            );
5320
5321
        try {
5322
            $this->partlyMockedContentService->updateContent($versionInfo, $contentUpdateStruct);
5323
        } catch (ContentFieldValidationException $e) {
5324
            $this->assertEquals($allFieldErrors, $e->getFieldErrors());
5325
            throw $e;
5326
        }
5327
    }
5328
5329
    /**
5330
     * Test for the updateContent() method.
5331
     *
5332
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForUpdate
5333
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForUpdate
5334
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContent
5335
     */
5336
    public function testUpdateContentTransactionRollback()
5337
    {
5338
        $this->expectException(\Exception::class);
5339
        $this->expectExceptionMessage('Store failed');
5340
5341
        $existingFields = [
5342
            new Field(
5343
                [
5344
                    'id' => '100',
5345
                    'fieldDefIdentifier' => 'identifier',
5346
                    'value' => 'initialValue',
5347
                    'languageCode' => 'eng-GB',
5348
                ]
5349
            ),
5350
        ];
5351
5352
        $fieldDefinitions = [
5353
            new FieldDefinition(
5354
                [
5355
                    'id' => 'fieldDefinitionId',
5356
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
5357
                    'isTranslatable' => false,
5358
                    'identifier' => 'identifier',
5359
                    'isRequired' => false,
5360
                    'defaultValue' => 'defaultValue',
5361
                ]
5362
            ),
5363
        ];
5364
5365
        // Setup a simple case that will pass
5366
        list($versionInfo, $contentUpdateStruct) = $this->assertForTestUpdateContentNonRedundantFieldSet(
5367
            'eng-US',
5368
            [],
5369
            [],
5370
            $existingFields,
5371
            $fieldDefinitions,
5372
            // Do not execute test
5373
            false
5374
        );
5375
5376
        $repositoryMock = $this->getRepositoryMock();
5377
        $repositoryMock->expects($this->never())->method('commit');
5378
        $repositoryMock->expects($this->once())->method('rollback');
5379
5380
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandlerMock */
5381
        $contentHandlerMock = $this->getPersistenceMock()->contentHandler();
5382
        $contentHandlerMock->expects($this->once())
5383
            ->method('updateContent')
5384
            ->with(
5385
                $this->anything(),
5386
                $this->anything(),
5387
                $this->anything()
5388
            )->will($this->throwException(new \Exception('Store failed')));
5389
5390
        // Execute
5391
        $this->partlyMockedContentService->updateContent($versionInfo, $contentUpdateStruct);
5392
    }
5393
5394
    /**
5395
     * Test for the copyContent() method.
5396
     *
5397
     * @covers \eZ\Publish\Core\Repository\ContentService::copyContent
5398
     */
5399
    public function testCopyContentThrowsUnauthorizedException()
5400
    {
5401
        $this->expectException(\eZ\Publish\Core\Base\Exceptions\UnauthorizedException::class);
5402
5403
        $repository = $this->getRepositoryMock();
5404
        $contentService = $this->getPartlyMockedContentService(['internalLoadContentInfo']);
5405
        $contentInfo = $this->createMock(APIContentInfo::class);
5406
        $locationCreateStruct = new LocationCreateStruct();
5407
        $location = new Location(['id' => $locationCreateStruct->parentLocationId]);
5408
        $locationServiceMock = $this->getLocationServiceMock();
5409
        $permissionResolver = $this->getPermissionResolverMock();
5410
5411
        $repository->expects($this->once())
5412
            ->method('getLocationService')
5413
            ->will($this->returnValue($locationServiceMock))
5414
        ;
5415
5416
        $locationServiceMock->expects($this->once())
5417
            ->method('loadLocation')
5418
            ->with(
5419
                $locationCreateStruct->parentLocationId
5420
            )
5421
            ->will($this->returnValue($location))
5422
        ;
5423
5424
        $contentInfo->expects($this->any())
5425
            ->method('__get')
5426
            ->with('sectionId')
5427
            ->will($this->returnValue(42));
5428
5429
        $permissionResolver
5430
            ->method('canUser')
5431
            ->with(
5432
                'content',
5433
                'create',
5434
                $contentInfo,
5435
                [$location]
5436
            )
5437
            ->will($this->returnValue(false));
5438
5439
        /* @var \eZ\Publish\API\Repository\Values\Content\ContentInfo $contentInfo */
5440
        $contentService->copyContent($contentInfo, $locationCreateStruct);
5441
    }
5442
5443
    /**
5444
     * Test for the copyContent() method.
5445
     *
5446
     * @covers \eZ\Publish\Core\Repository\ContentService::copyContent
5447
     * @covers \eZ\Publish\Core\Repository\ContentService::getDefaultObjectStates
5448
     * @covers \eZ\Publish\Core\Repository\ContentService::internalPublishVersion
5449
     */
5450
    public function testCopyContent()
5451
    {
5452
        $repositoryMock = $this->getRepositoryMock();
5453
        $contentService = $this->getPartlyMockedContentService([
5454
            'internalLoadContentInfo',
5455
            'internalLoadContent',
5456
            'getUnixTimestamp',
5457
        ]);
5458
        $locationServiceMock = $this->getLocationServiceMock();
5459
        $contentInfoMock = $this->createMock(APIContentInfo::class);
5460
        $locationCreateStruct = new LocationCreateStruct();
5461
        $location = new Location(['id' => $locationCreateStruct->parentLocationId]);
5462
        $user = $this->getStubbedUser(14);
5463
5464
        $permissionResolverMock = $this->getPermissionResolverMock();
5465
5466
        $permissionResolverMock
5467
            ->method('getCurrentUserReference')
5468
            ->willReturn($user);
5469
5470
        $repositoryMock
5471
            ->method('getPermissionResolver')
5472
            ->willReturn($permissionResolverMock);
5473
5474
        $repositoryMock->expects($this->exactly(3))
5475
            ->method('getLocationService')
5476
            ->will($this->returnValue($locationServiceMock));
5477
5478
        $locationServiceMock->expects($this->once())
5479
            ->method('loadLocation')
5480
            ->with($locationCreateStruct->parentLocationId)
5481
            ->will($this->returnValue($location))
5482
        ;
5483
5484
        $contentInfoMock->expects($this->any())
5485
            ->method('__get')
5486
            ->will(
5487
                $this->returnValueMap(
5488
                    [
5489
                        ['isHidden', true],
5490
                        ['id', 42],
5491
                    ]
5492
                )
5493
            );
5494
        $versionInfoMock = $this->createMock(APIVersionInfo::class);
5495
5496
        $versionInfoMock->expects($this->any())
5497
            ->method('__get')
5498
            ->will(
5499
                $this->returnValueMap(
5500
                    [
5501
                        ['versionNo', 123],
5502
                    ]
5503
                )
5504
            );
5505
5506
        $versionInfoMock->expects($this->once())
5507
            ->method('isDraft')
5508
            ->willReturn(true);
5509
5510
        $versionInfoMock->expects($this->once())
5511
            ->method('getContentInfo')
5512
            ->will($this->returnValue($contentInfoMock));
5513
5514
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandlerMock */
5515
        $contentHandlerMock = $this->getPersistenceMock()->contentHandler();
5516
        $domainMapperMock = $this->getDomainMapperMock();
5517
5518
        $repositoryMock->expects($this->once())->method('beginTransaction');
5519
        $repositoryMock->expects($this->once())->method('commit');
5520
5521
        $permissionResolverMock
5522
            ->method('canUser')
5523
            ->willReturnMap(
5524
                [
5525
                    ['content', 'create', $contentInfoMock, [$location], true],
5526
                    ['content', 'manage_locations', $contentInfoMock, [$location], true],
5527
                ]
5528
            );
5529
5530
        $spiContentInfo = new SPIContentInfo(['id' => 42]);
5531
        $spiVersionInfo = new SPIVersionInfo(
5532
            [
5533
                'contentInfo' => $spiContentInfo,
5534
                'creationDate' => 123456,
5535
            ]
5536
        );
5537
        $spiContent = new SPIContent(['versionInfo' => $spiVersionInfo]);
5538
        $contentHandlerMock->expects($this->once())
5539
            ->method('copy')
5540
            ->with(42, null)
5541
            ->will($this->returnValue($spiContent));
5542
5543
        $this->mockGetDefaultObjectStates();
5544
        $this->mockSetDefaultObjectStates();
5545
5546
        $domainMapperMock->expects($this->once())
5547
            ->method('buildVersionInfoDomainObject')
5548
            ->with($spiVersionInfo)
5549
            ->will($this->returnValue($versionInfoMock));
5550
5551
        /* @var \eZ\Publish\API\Repository\Values\Content\VersionInfo $versionInfoMock */
5552
        $content = $this->mockPublishVersion(123456, 126666, true);
5553
        $locationServiceMock->expects($this->once())
5554
            ->method('createLocation')
5555
            ->with(
5556
                $content->getVersionInfo()->getContentInfo(),
5557
                $locationCreateStruct
5558
            );
5559
5560
        $contentService->expects($this->once())
5561
            ->method('internalLoadContent')
5562
            ->with(
5563
                $content->id
5564
            )
5565
            ->will($this->returnValue($content));
5566
5567
        $contentService->expects($this->once())
5568
            ->method('getUnixTimestamp')
5569
            ->will($this->returnValue(126666));
5570
5571
        /* @var \eZ\Publish\API\Repository\Values\Content\ContentInfo $contentInfoMock */
5572
        $contentService->copyContent($contentInfoMock, $locationCreateStruct, null);
5573
    }
5574
5575
    /**
5576
     * Test for the copyContent() method.
5577
     *
5578
     * @covers \eZ\Publish\Core\Repository\ContentService::copyContent
5579
     * @covers \eZ\Publish\Core\Repository\ContentService::getDefaultObjectStates
5580
     * @covers \eZ\Publish\Core\Repository\ContentService::internalPublishVersion
5581
     */
5582
    public function testCopyContentWithVersionInfo()
5583
    {
5584
        $repositoryMock = $this->getRepositoryMock();
5585
        $contentService = $this->getPartlyMockedContentService([
5586
            'internalLoadContentInfo',
5587
            'internalLoadContent',
5588
            'getUnixTimestamp',
5589
        ]);
5590
        $locationServiceMock = $this->getLocationServiceMock();
5591
        $contentInfoMock = $this->createMock(APIContentInfo::class);
5592
        $locationCreateStruct = new LocationCreateStruct();
5593
        $location = new Location(['id' => $locationCreateStruct->parentLocationId]);
5594
        $user = $this->getStubbedUser(14);
5595
5596
        $permissionResolverMock = $this->getPermissionResolverMock();
5597
5598
        $permissionResolverMock
5599
            ->method('getCurrentUserReference')
5600
            ->willReturn($user);
5601
5602
        $repositoryMock
5603
            ->method('getPermissionResolver')
5604
            ->willReturn($permissionResolverMock);
5605
5606
        $repositoryMock->expects($this->exactly(3))
5607
            ->method('getLocationService')
5608
            ->will($this->returnValue($locationServiceMock));
5609
5610
        $locationServiceMock->expects($this->once())
5611
            ->method('loadLocation')
5612
            ->with($locationCreateStruct->parentLocationId)
5613
            ->will($this->returnValue($location))
5614
        ;
5615
5616
        $contentInfoMock->expects($this->any())
5617
            ->method('__get')
5618
            ->will(
5619
                $this->returnValueMap([
5620
                    ['isHidden', true],
5621
                    ['id', 42],
5622
                ])
5623
            );
5624
5625
        $versionInfoMock = $this->createMock(APIVersionInfo::class);
5626
5627
        $versionInfoMock->expects($this->any())
5628
            ->method('__get')
5629
            ->will(
5630
                $this->returnValueMap(
5631
                    [
5632
                        ['versionNo', 123],
5633
                    ]
5634
                )
5635
            );
5636
        $versionInfoMock->expects($this->once())
5637
            ->method('isDraft')
5638
            ->willReturn(true);
5639
        $versionInfoMock->expects($this->once())
5640
            ->method('getContentInfo')
5641
            ->will($this->returnValue($contentInfoMock));
5642
5643
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandlerMock */
5644
        $contentHandlerMock = $this->getPersistenceMock()->contentHandler();
5645
        $domainMapperMock = $this->getDomainMapperMock();
5646
5647
        $repositoryMock->expects($this->once())->method('beginTransaction');
5648
        $repositoryMock->expects($this->once())->method('commit');
5649
5650
        $permissionResolverMock
5651
            ->method('canUser')
5652
            ->willReturnMap(
5653
                [
5654
                    ['content', 'create', $contentInfoMock, [$location], true],
5655
                    ['content', 'manage_locations', $contentInfoMock, [$location], true],
5656
                ]
5657
            );
5658
5659
        $spiContentInfo = new SPIContentInfo(['id' => 42]);
5660
        $spiVersionInfo = new SPIVersionInfo(
5661
            [
5662
                'contentInfo' => $spiContentInfo,
5663
                'creationDate' => 123456,
5664
            ]
5665
        );
5666
        $spiContent = new SPIContent(['versionInfo' => $spiVersionInfo]);
5667
        $contentHandlerMock->expects($this->once())
5668
            ->method('copy')
5669
            ->with(42, 123)
5670
            ->will($this->returnValue($spiContent));
5671
5672
        $this->mockGetDefaultObjectStates();
5673
        $this->mockSetDefaultObjectStates();
5674
5675
        $domainMapperMock->expects($this->once())
5676
            ->method('buildVersionInfoDomainObject')
5677
            ->with($spiVersionInfo)
5678
            ->will($this->returnValue($versionInfoMock));
5679
5680
        /* @var \eZ\Publish\API\Repository\Values\Content\VersionInfo $versionInfoMock */
5681
        $content = $this->mockPublishVersion(123456, 126666, true);
5682
        $locationServiceMock->expects($this->once())
5683
            ->method('createLocation')
5684
            ->with(
5685
                $content->getVersionInfo()->getContentInfo(),
5686
                $locationCreateStruct
5687
            );
5688
5689
        $contentService->expects($this->once())
5690
            ->method('internalLoadContent')
5691
            ->with(
5692
                $content->id
5693
            )
5694
            ->will($this->returnValue($content));
5695
5696
        $contentService->expects($this->once())
5697
            ->method('getUnixTimestamp')
5698
            ->will($this->returnValue(126666));
5699
5700
        /* @var \eZ\Publish\API\Repository\Values\Content\ContentInfo $contentInfoMock */
5701
        $contentService->copyContent($contentInfoMock, $locationCreateStruct, $versionInfoMock);
5702
    }
5703
5704
    /**
5705
     * Test for the copyContent() method.
5706
     *
5707
     * @covers \eZ\Publish\Core\Repository\ContentService::copyContent
5708
     * @covers \eZ\Publish\Core\Repository\ContentService::getDefaultObjectStates
5709
     * @covers \eZ\Publish\Core\Repository\ContentService::internalPublishVersion
5710
     */
5711
    public function testCopyContentWithRollback()
5712
    {
5713
        $this->expectException(\Exception::class);
5714
        $this->expectExceptionMessage('Handler threw an exception');
5715
5716
        $repositoryMock = $this->getRepositoryMock();
5717
        $contentService = $this->getPartlyMockedContentService();
5718
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandlerMock */
5719
        $contentHandlerMock = $this->getPersistenceMock()->contentHandler();
5720
        $locationCreateStruct = new LocationCreateStruct();
5721
        $location = new Location(['id' => $locationCreateStruct->parentLocationId]);
5722
        $locationServiceMock = $this->getLocationServiceMock();
5723
        $user = $this->getStubbedUser(14);
5724
5725
        $permissionResolverMock = $this->getPermissionResolverMock();
5726
5727
        $permissionResolverMock
5728
            ->method('getCurrentUserReference')
5729
            ->willReturn($user);
5730
5731
        $repositoryMock
5732
            ->method('getPermissionResolver')
5733
            ->willReturn($permissionResolverMock);
5734
5735
        $repositoryMock->expects($this->once())
5736
            ->method('getLocationService')
5737
            ->will($this->returnValue($locationServiceMock))
5738
        ;
5739
5740
        $locationServiceMock->expects($this->once())
5741
            ->method('loadLocation')
5742
            ->with($locationCreateStruct->parentLocationId)
5743
            ->will($this->returnValue($location))
5744
        ;
5745
5746
        $contentInfoMock = $this->createMock(APIContentInfo::class);
5747
        $contentInfoMock->expects($this->any())
5748
            ->method('__get')
5749
            ->with('id')
5750
            ->will($this->returnValue(42));
5751
5752
        $this->mockGetDefaultObjectStates();
5753
5754
        $repositoryMock->expects($this->once())->method('beginTransaction');
5755
        $repositoryMock->expects($this->once())->method('rollback');
5756
5757
        $permissionResolverMock
5758
            ->method('canUser')
5759
            ->willReturnMap(
5760
                [
5761
                    ['content', 'create', $contentInfoMock, [$location], true],
5762
                    ['content', 'manage_locations', $contentInfoMock, [$location], true],
5763
                ]
5764
            );
5765
5766
        $contentHandlerMock->expects($this->once())
5767
            ->method('copy')
5768
            ->with(42, null)
5769
            ->will($this->throwException(new Exception('Handler threw an exception')));
5770
5771
        /* @var \eZ\Publish\API\Repository\Values\Content\ContentInfo $contentInfoMock */
5772
        $contentService->copyContent($contentInfoMock, $locationCreateStruct, null);
5773
    }
5774
5775
    /**
5776
     * Reusable method for setting exceptions on buildContentDomainObject usage.
5777
     *
5778
     * Plain usage as in when content type is loaded directly.
5779
     *
5780
     * @param \eZ\Publish\SPI\Persistence\Content $spiContent
5781
     * @param array $translations
5782
     * @param bool $useAlwaysAvailable
5783
     *
5784
     * @return \PHPUnit\Framework\MockObject\MockObject|\eZ\Publish\API\Repository\Values\Content\Content
5785
     */
5786
    private function mockBuildContentDomainObject(SPIContent $spiContent, array $translations = null, bool $useAlwaysAvailable = null)
5787
    {
5788
        $contentTypeId = $spiContent->versionInfo->contentInfo->contentTypeId;
5789
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
5790
        $repositoryMock = $this->getRepositoryMock();
5791
5792
        $contentType = new ContentType([
5793
            'id' => $contentTypeId,
5794
            'fieldDefinitions' => [],
5795
        ]);
5796
5797
        $repositoryMock->expects($this->once())
5798
            ->method('getContentTypeService')
5799
            ->willReturn($contentTypeServiceMock);
5800
5801
        $contentTypeServiceMock->expects($this->once())
5802
            ->method('loadContentType')
5803
            ->with($this->equalTo($contentTypeId))
5804
            ->willReturn($contentType);
5805
5806
        $content = $this->createMock(APIContent::class);
5807
5808
        $this->getDomainMapperMock()
5809
            ->expects($this->once())
5810
            ->method('buildContentDomainObject')
5811
            ->with($spiContent, $contentType, $translations ?? [], $useAlwaysAvailable)
5812
            ->willReturn($content);
5813
5814
        return $content;
5815
    }
5816
5817
    protected function mockGetDefaultObjectStates()
5818
    {
5819
        /** @var \PHPUnit\Framework\MockObject\MockObject $objectStateHandlerMock */
5820
        $objectStateHandlerMock = $this->getPersistenceMock()->objectStateHandler();
5821
5822
        $objectStateGroups = [
5823
            new SPIObjectStateGroup(['id' => 10]),
5824
            new SPIObjectStateGroup(['id' => 20]),
5825
        ];
5826
5827
        /* @var \PHPUnit\Framework\MockObject\MockObject $objectStateHandlerMock */
5828
        $objectStateHandlerMock->expects($this->once())
5829
            ->method('loadAllGroups')
5830
            ->will($this->returnValue($objectStateGroups));
5831
5832
        $objectStateHandlerMock->expects($this->at(1))
5833
            ->method('loadObjectStates')
5834
            ->with($this->equalTo(10))
5835
            ->will(
5836
                $this->returnValue(
5837
                    [
5838
                        new SPIObjectState(['id' => 11, 'groupId' => 10]),
5839
                        new SPIObjectState(['id' => 12, 'groupId' => 10]),
5840
                    ]
5841
                )
5842
            );
5843
5844
        $objectStateHandlerMock->expects($this->at(2))
5845
            ->method('loadObjectStates')
5846
            ->with($this->equalTo(20))
5847
            ->will(
5848
                $this->returnValue(
5849
                    [
5850
                        new SPIObjectState(['id' => 21, 'groupId' => 20]),
5851
                        new SPIObjectState(['id' => 22, 'groupId' => 20]),
5852
                    ]
5853
                )
5854
            );
5855
    }
5856
5857
    protected function mockSetDefaultObjectStates()
5858
    {
5859
        /** @var \PHPUnit\Framework\MockObject\MockObject $objectStateHandlerMock */
5860
        $objectStateHandlerMock = $this->getPersistenceMock()->objectStateHandler();
5861
5862
        $defaultObjectStates = [
5863
            new SPIObjectState(['id' => 11, 'groupId' => 10]),
5864
            new SPIObjectState(['id' => 21, 'groupId' => 20]),
5865
        ];
5866
        foreach ($defaultObjectStates as $index => $objectState) {
5867
            $objectStateHandlerMock->expects($this->at($index + 3))
5868
                ->method('setContentState')
5869
                ->with(
5870
                    42,
5871
                    $objectState->groupId,
5872
                    $objectState->id
5873
                );
5874
        }
5875
    }
5876
5877
    /**
5878
     * @param int|null $publicationDate
5879
     * @param int|null $modificationDate
5880
     * @param bool $isHidden
5881
     *
5882
     * @return \eZ\Publish\API\Repository\Values\Content\Content
5883
     */
5884
    protected function mockPublishVersion($publicationDate = null, $modificationDate = null, $isHidden = false)
5885
    {
5886
        $versionInfoMock = $this->createMock(APIVersionInfo::class);
5887
        $contentInfoMock = $this->createMock(APIContentInfo::class);
5888
        /* @var \PHPUnit\Framework\MockObject\MockObject $contentHandlerMock */
5889
        $contentHandlerMock = $this->getPersistenceMock()->contentHandler();
5890
        $metadataUpdateStruct = new SPIMetadataUpdateStruct();
5891
5892
        $spiContent = new SPIContent([
5893
            'versionInfo' => new VersionInfo([
5894
                    'contentInfo' => new ContentInfo(['id' => 42, 'contentTypeId' => 123]),
5895
            ]),
5896
        ]);
5897
5898
        $contentMock = $this->mockBuildContentDomainObject($spiContent);
5899
        $contentMock->expects($this->any())
5900
            ->method('__get')
5901
            ->will(
5902
                $this->returnValueMap(
5903
                    [
5904
                        ['id', 42],
5905
                        ['contentInfo', $contentInfoMock],
5906
                        ['versionInfo', $versionInfoMock],
5907
                    ]
5908
                )
5909
            );
5910
        $contentMock->expects($this->any())
5911
            ->method('getVersionInfo')
5912
            ->will($this->returnValue($versionInfoMock));
5913
        $versionInfoMock->expects($this->any())
5914
            ->method('getContentInfo')
5915
            ->will($this->returnValue($contentInfoMock));
5916
        $versionInfoMock->expects($this->any())
5917
            ->method('__get')
5918
            ->will(
5919
                $this->returnValueMap(
5920
                    [
5921
                        ['languageCodes', ['eng-GB']],
5922
                    ]
5923
                )
5924
            );
5925
        $contentInfoMock->expects($this->any())
5926
            ->method('__get')
5927
            ->will(
5928
                $this->returnValueMap(
5929
                    [
5930
                        ['alwaysAvailable', true],
5931
                        ['mainLanguageCode', 'eng-GB'],
5932
                    ]
5933
                )
5934
            );
5935
5936
        $currentTime = time();
5937
        if ($publicationDate === null && $versionInfoMock->versionNo === 1) {
5938
            $publicationDate = $currentTime;
5939
        }
5940
5941
        // Account for 1 second of test execution time
5942
        $metadataUpdateStruct->publicationDate = $publicationDate;
5943
        $metadataUpdateStruct->modificationDate = $modificationDate ?? $currentTime;
5944
        $metadataUpdateStruct->isHidden = $isHidden;
5945
5946
        $contentHandlerMock->expects($this->once())
5947
            ->method('publish')
5948
            ->with(
5949
                42,
5950
                123,
5951
                $metadataUpdateStruct
5952
            )
5953
            ->will($this->returnValue($spiContent));
5954
5955
        /* @var \eZ\Publish\API\Repository\Values\Content\Content $contentMock */
5956
        $this->mockPublishUrlAliasesForContent($contentMock);
5957
5958
        return $contentMock;
5959
    }
5960
5961
    /**
5962
     * @param \eZ\Publish\API\Repository\Values\Content\Content $content
5963
     */
5964
    protected function mockPublishUrlAliasesForContent(APIContent $content)
5965
    {
5966
        $nameSchemaServiceMock = $this->getNameSchemaServiceMock();
5967
        /** @var \PHPUnit\Framework\MockObject\MockObject $urlAliasHandlerMock */
5968
        $urlAliasHandlerMock = $this->getPersistenceMock()->urlAliasHandler();
5969
        $locationServiceMock = $this->getLocationServiceMock();
5970
        $location = $this->createMock(APILocation::class);
5971
5972
        $location->expects($this->at(0))
5973
            ->method('__get')
5974
            ->with('id')
5975
            ->will($this->returnValue(123));
5976
        $location->expects($this->at(1))
5977
            ->method('__get')
5978
            ->with('parentLocationId')
5979
            ->will($this->returnValue(456));
5980
5981
        $urlAliasNames = ['eng-GB' => 'hello'];
5982
        $nameSchemaServiceMock->expects($this->once())
5983
            ->method('resolveUrlAliasSchema')
5984
            ->with($content)
5985
            ->will($this->returnValue($urlAliasNames));
5986
5987
        $locationServiceMock->expects($this->once())
5988
            ->method('loadLocations')
5989
            ->with($content->getVersionInfo()->getContentInfo())
5990
            ->will($this->returnValue([$location]));
5991
5992
        $urlAliasHandlerMock->expects($this->once())
5993
            ->method('publishUrlAliasForLocation')
5994
            ->with(123, 456, 'hello', 'eng-GB', true, true);
5995
5996
        $location->expects($this->at(2))
5997
            ->method('__get')
5998
            ->with('id')
5999
            ->will($this->returnValue(123));
6000
6001
        $location->expects($this->at(3))
6002
            ->method('__get')
6003
            ->with('parentLocationId')
6004
            ->will($this->returnValue(456));
6005
6006
        $urlAliasHandlerMock->expects($this->once())
6007
            ->method('archiveUrlAliasesForDeletedTranslations')
6008
            ->with(123, 456, ['eng-GB']);
6009
    }
6010
6011
    protected $domainMapperMock;
6012
6013
    /**
6014
     * @return \PHPUnit\Framework\MockObject\MockObject|\eZ\Publish\Core\Repository\Helper\DomainMapper
6015
     */
6016
    protected function getDomainMapperMock()
6017
    {
6018
        if (!isset($this->domainMapperMock)) {
6019
            $this->domainMapperMock = $this->createMock(DomainMapper::class);
6020
        }
6021
6022
        return $this->domainMapperMock;
6023
    }
6024
6025
    protected $relationProcessorMock;
6026
6027
    /**
6028
     * @return \PHPUnit\Framework\MockObject\MockObject|\eZ\Publish\Core\Repository\Helper\RelationProcessor
6029
     */
6030
    protected function getRelationProcessorMock()
6031
    {
6032
        if (!isset($this->relationProcessorMock)) {
6033
            $this->relationProcessorMock = $this->createMock(RelationProcessor::class);
6034
        }
6035
6036
        return $this->relationProcessorMock;
6037
    }
6038
6039
    protected $nameSchemaServiceMock;
6040
6041
    /**
6042
     * @return \PHPUnit\Framework\MockObject\MockObject|\eZ\Publish\Core\Repository\Helper\NameSchemaService
6043
     */
6044
    protected function getNameSchemaServiceMock()
6045
    {
6046
        if (!isset($this->nameSchemaServiceMock)) {
6047
            $this->nameSchemaServiceMock = $this->createMock(NameSchemaService::class);
6048
        }
6049
6050
        return $this->nameSchemaServiceMock;
6051
    }
6052
6053
    protected $contentTypeServiceMock;
6054
6055
    /**
6056
     * @return \PHPUnit\Framework\MockObject\MockObject|\eZ\Publish\API\Repository\ContentTypeService
6057
     */
6058
    protected function getContentTypeServiceMock()
6059
    {
6060
        if (!isset($this->contentTypeServiceMock)) {
6061
            $this->contentTypeServiceMock = $this->createMock(APIContentTypeService::class);
6062
        }
6063
6064
        return $this->contentTypeServiceMock;
6065
    }
6066
6067
    protected $locationServiceMock;
6068
6069
    /**
6070
     * @return \PHPUnit\Framework\MockObject\MockObject|\eZ\Publish\API\Repository\LocationService
6071
     */
6072
    protected function getLocationServiceMock()
6073
    {
6074
        if (!isset($this->locationServiceMock)) {
6075
            $this->locationServiceMock = $this->createMock(APILocationService::class);
6076
        }
6077
6078
        return $this->locationServiceMock;
6079
    }
6080
6081
    /** @var \eZ\Publish\Core\Repository\ContentService */
6082
    protected $partlyMockedContentService;
6083
6084
    /**
6085
     * Returns the content service to test with $methods mocked.
6086
     *
6087
     * Injected Repository comes from {@see getRepositoryMock()} and persistence handler from {@see getPersistenceMock()}
6088
     *
6089
     * @param string[] $methods
6090
     *
6091
     * @return \eZ\Publish\Core\Repository\ContentService|\PHPUnit\Framework\MockObject\MockObject
6092
     */
6093
    protected function getPartlyMockedContentService(array $methods = null)
6094
    {
6095
        if (!isset($this->partlyMockedContentService)) {
6096
            $this->partlyMockedContentService = $this->getMockBuilder(ContentService::class)
6097
                ->setMethods($methods)
6098
                ->setConstructorArgs(
6099
                    [
6100
                        $this->getRepositoryMock(),
6101
                        $this->getPersistenceMock(),
6102
                        $this->getDomainMapperMock(),
6103
                        $this->getRelationProcessorMock(),
6104
                        $this->getNameSchemaServiceMock(),
6105
                        $this->getFieldTypeRegistryMock(),
6106
                        $this->getPermissionResolverMock(),
6107
                        [],
6108
                    ]
6109
                )
6110
                ->getMock();
6111
        }
6112
6113
        return $this->partlyMockedContentService;
6114
    }
6115
6116
    /**
6117
     * @return \eZ\Publish\API\Repository\Repository|\PHPUnit\Framework\MockObject\MockObject
6118
     */
6119
    protected function getRepositoryMock(): Repository
6120
    {
6121
        $repositoryMock = parent::getRepositoryMock();
6122
        $repositoryMock
6123
            ->expects($this->any())
6124
            ->method('getPermissionResolver')
6125
            ->willReturn($this->getPermissionResolverMock());
6126
6127
        return $repositoryMock;
6128
    }
6129
}
6130