Completed
Push — location_references ( 47d67d...79f396 )
by
unknown
13:04
created

providerForTestCreateContentWithInvalidLanguage()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 29

Duplication

Lines 29
Ratio 100 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 29
loc 29
rs 9.456
c 0
b 0
f 0
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
        $settings = ['default_version_archive_limit' => 10];
81
82
        $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...
83
            $repositoryMock,
0 ignored issues
show
Bug introduced by
It seems like $repositoryMock defined by $this->getRepositoryMock() on line 73 can also be of type object<PHPUnit\Framework\MockObject\MockObject>; however, eZ\Publish\Core\Reposito...tService::__construct() does only seem to accept object<eZ\Publish\API\Repository\Repository>, maybe add an additional type check?

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

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

    return array();
}

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

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

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

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

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

    return array();
}

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

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

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

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

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

    return array();
}

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

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

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

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

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

    return array();
}

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

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

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

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

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

    return array();
}

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

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

Loading history...
89
            $settings
90
        );
91
    }
92
93
    /**
94
     * Test for the loadVersionInfo() method, of published version.
95
     *
96
     * @covers \eZ\Publish\Core\Repository\ContentService::loadVersionInfoById
97
     */
98
    public function testLoadVersionInfoById()
99
    {
100
        $repository = $this->getRepositoryMock();
101
        $contentServiceMock = $this->getPartlyMockedContentService(['loadContentInfo']);
102
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandler */
103
        $contentHandler = $this->getPersistenceMock()->contentHandler();
104
        $domainMapperMock = $this->getDomainMapperMock();
105
        $versionInfoMock = $this->createMock(APIVersionInfo::class);
106
107
        $versionInfoMock->expects($this->once())
108
            ->method('isPublished')
109
            ->willReturn(true);
110
111
        $contentServiceMock->expects($this->never())
112
            ->method('loadContentInfo');
113
114
        $contentHandler->expects($this->once())
115
            ->method('loadVersionInfo')
116
            ->with(
117
                $this->equalTo(42),
118
                $this->equalTo(null)
119
            )->will(
120
                $this->returnValue(new SPIVersionInfo())
121
            );
122
123
        $domainMapperMock->expects($this->once())
124
            ->method('buildVersionInfoDomainObject')
125
            ->with(new SPIVersionInfo())
126
            ->will($this->returnValue($versionInfoMock));
127
128
        $repository->expects($this->once())
129
            ->method('canUser')
130
            ->with(
131
                $this->equalTo('content'),
132
                $this->equalTo('read'),
133
                $this->equalTo($versionInfoMock)
134
            )->will($this->returnValue(true));
135
136
        $result = $contentServiceMock->loadVersionInfoById(42);
137
138
        $this->assertEquals($versionInfoMock, $result);
139
    }
140
141
    /**
142
     * Test for the loadVersionInfo() method, of a draft.
143
     *
144
     * @depends testLoadVersionInfoById
145
     * @covers \eZ\Publish\Core\Repository\ContentService::loadVersionInfoById
146
     */
147
    public function testLoadVersionInfoByIdAndVersionNumber()
148
    {
149
        $repository = $this->getRepositoryMock();
150
        $contentServiceMock = $this->getPartlyMockedContentService(['loadContentInfo']);
151
        /** @var \PHPUnit_Framework_MockObject_MockObject $contentHandler */
152
        $contentHandler = $this->getPersistenceMock()->contentHandler();
153
        $domainMapperMock = $this->getDomainMapperMock();
154
        $versionInfoMock = $this->createMock(APIVersionInfo::class);
155
156
        $versionInfoMock->expects($this->any())
157
            ->method('__get')
158
            ->with('status')
159
            ->willReturn(APIVersionInfo::STATUS_DRAFT);
160
161
        $contentServiceMock->expects($this->never())
162
            ->method('loadContentInfo');
163
164
        $contentHandler->expects($this->once())
165
            ->method('loadVersionInfo')
166
            ->with(
167
                $this->equalTo(42),
168
                $this->equalTo(2)
169
            )->willReturn(new SPIVersionInfo());
170
171
        $domainMapperMock->expects($this->once())
172
            ->method('buildVersionInfoDomainObject')
173
            ->with(new SPIVersionInfo())
174
            ->willReturn($versionInfoMock);
175
176
        $repository->expects($this->once())
177
            ->method('canUser')
178
            ->with(
179
                $this->equalTo('content'),
180
                $this->equalTo('versionread'),
181
                $this->equalTo($versionInfoMock)
182
            )->willReturn(true);
183
184
        $result = $contentServiceMock->loadVersionInfoById(42, 2);
185
186
        $this->assertEquals($versionInfoMock, $result);
187
    }
188
189
    /**
190
     * Test for the loadVersionInfo() method.
191
     *
192
     * @covers \eZ\Publish\Core\Repository\ContentService::loadVersionInfoById
193
     */
194
    public function testLoadVersionInfoByIdThrowsNotFoundException()
195
    {
196
        $this->expectException(\eZ\Publish\Core\Base\Exceptions\NotFoundException::class);
197
198
        $contentServiceMock = $this->getPartlyMockedContentService(['loadContentInfo']);
199
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandler */
200
        $contentHandler = $this->getPersistenceMock()->contentHandler();
201
202
        $contentHandler->expects($this->once())
203
            ->method('loadVersionInfo')
204
            ->with(
205
                $this->equalTo(42),
206
                $this->equalTo(24)
207
            )->will(
208
                $this->throwException(
209
                    new NotFoundException(
210
                        'Content',
211
                        [
212
                            'contentId' => 42,
213
                            'versionNo' => 24,
214
                        ]
215
                    )
216
                )
217
            );
218
219
        $contentServiceMock->loadVersionInfoById(42, 24);
220
    }
221
222
    /**
223
     * Test for the loadVersionInfo() method.
224
     *
225
     * @covers \eZ\Publish\Core\Repository\ContentService::loadVersionInfoById
226
     */
227
    public function testLoadVersionInfoByIdThrowsUnauthorizedExceptionNonPublishedVersion()
228
    {
229
        $this->expectException(\eZ\Publish\Core\Base\Exceptions\UnauthorizedException::class);
230
231
        $repository = $this->getRepositoryMock();
232
        $contentServiceMock = $this->getPartlyMockedContentService();
233
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandler */
234
        $contentHandler = $this->getPersistenceMock()->contentHandler();
235
        $domainMapperMock = $this->getDomainMapperMock();
236
        $versionInfoMock = $this->createMock(APIVersionInfo::class);
237
238
        $versionInfoMock->expects($this->any())
239
            ->method('isPublished')
240
            ->willReturn(false);
241
242
        $contentHandler->expects($this->once())
243
            ->method('loadVersionInfo')
244
            ->with(
245
                $this->equalTo(42),
246
                $this->equalTo(24)
247
            )->will(
248
                $this->returnValue(new SPIVersionInfo())
249
            );
250
251
        $domainMapperMock->expects($this->once())
252
            ->method('buildVersionInfoDomainObject')
253
            ->with(new SPIVersionInfo())
254
            ->will($this->returnValue($versionInfoMock));
255
256
        $repository->expects($this->once())
257
            ->method('canUser')
258
            ->with(
259
                $this->equalTo('content'),
260
                $this->equalTo('versionread'),
261
                $this->equalTo($versionInfoMock)
262
            )->will($this->returnValue(false));
263
264
        $contentServiceMock->loadVersionInfoById(42, 24);
265
    }
266
267
    /**
268
     * Test for the loadVersionInfo() method.
269
     *
270
     * @covers \eZ\Publish\Core\Repository\ContentService::loadVersionInfoById
271
     */
272 View Code Duplication
    public function testLoadVersionInfoByIdPublishedVersion()
273
    {
274
        $repository = $this->getRepositoryMock();
275
        $contentServiceMock = $this->getPartlyMockedContentService();
276
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandler */
277
        $contentHandler = $this->getPersistenceMock()->contentHandler();
278
        $domainMapperMock = $this->getDomainMapperMock();
279
        $versionInfoMock = $this->createMock(APIVersionInfo::class);
280
281
        $versionInfoMock->expects($this->once())
282
            ->method('isPublished')
283
            ->willReturn(true);
284
285
        $contentHandler->expects($this->once())
286
            ->method('loadVersionInfo')
287
            ->with(
288
                $this->equalTo(42),
289
                $this->equalTo(24)
290
            )->will(
291
                $this->returnValue(new SPIVersionInfo())
292
            );
293
294
        $domainMapperMock->expects($this->once())
295
            ->method('buildVersionInfoDomainObject')
296
            ->with(new SPIVersionInfo())
297
            ->will($this->returnValue($versionInfoMock));
298
299
        $repository->expects($this->once())
300
            ->method('canUser')
301
            ->with(
302
                $this->equalTo('content'),
303
                $this->equalTo('read'),
304
                $this->equalTo($versionInfoMock)
305
            )->will($this->returnValue(true));
306
307
        $result = $contentServiceMock->loadVersionInfoById(42, 24);
308
309
        $this->assertEquals($versionInfoMock, $result);
310
    }
311
312
    /**
313
     * Test for the loadVersionInfo() method.
314
     *
315
     * @covers \eZ\Publish\Core\Repository\ContentService::loadVersionInfoById
316
     */
317 View Code Duplication
    public function testLoadVersionInfoByIdNonPublishedVersion()
318
    {
319
        $repository = $this->getRepositoryMock();
320
        $contentServiceMock = $this->getPartlyMockedContentService();
321
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandler */
322
        $contentHandler = $this->getPersistenceMock()->contentHandler();
323
        $domainMapperMock = $this->getDomainMapperMock();
324
        $versionInfoMock = $this->createMock(APIVersionInfo::class);
325
326
        $versionInfoMock->expects($this->once())
327
            ->method('isPublished')
328
            ->willReturn(false);
329
330
        $contentHandler->expects($this->once())
331
            ->method('loadVersionInfo')
332
            ->with(
333
                $this->equalTo(42),
334
                $this->equalTo(24)
335
            )->will(
336
                $this->returnValue(new SPIVersionInfo())
337
            );
338
339
        $domainMapperMock->expects($this->once())
340
            ->method('buildVersionInfoDomainObject')
341
            ->with(new SPIVersionInfo())
342
            ->will($this->returnValue($versionInfoMock));
343
344
        $repository->expects($this->once())
345
            ->method('canUser')
346
            ->with(
347
                $this->equalTo('content'),
348
                $this->equalTo('versionread'),
349
                $this->equalTo($versionInfoMock)
350
            )->will($this->returnValue(true));
351
352
        $result = $contentServiceMock->loadVersionInfoById(42, 24);
353
354
        $this->assertEquals($versionInfoMock, $result);
355
    }
356
357
    /**
358
     * Test for the loadVersionInfo() method.
359
     *
360
     * @covers \eZ\Publish\Core\Repository\ContentService::loadVersionInfo
361
     * @depends eZ\Publish\Core\Repository\Tests\Service\Mock\ContentTest::testLoadVersionInfoById
362
     * @depends eZ\Publish\Core\Repository\Tests\Service\Mock\ContentTest::testLoadVersionInfoByIdThrowsNotFoundException
363
     * @depends eZ\Publish\Core\Repository\Tests\Service\Mock\ContentTest::testLoadVersionInfoByIdThrowsUnauthorizedExceptionNonPublishedVersion
364
     * @depends eZ\Publish\Core\Repository\Tests\Service\Mock\ContentTest::testLoadVersionInfoByIdPublishedVersion
365
     * @depends eZ\Publish\Core\Repository\Tests\Service\Mock\ContentTest::testLoadVersionInfoByIdNonPublishedVersion
366
     */
367
    public function testLoadVersionInfo()
368
    {
369
        $contentServiceMock = $this->getPartlyMockedContentService(
370
            ['loadVersionInfoById']
371
        );
372
        $contentServiceMock->expects(
373
            $this->once()
374
        )->method(
375
            'loadVersionInfoById'
376
        )->with(
377
            $this->equalTo(42),
378
            $this->equalTo(7)
379
        )->will(
380
            $this->returnValue('result')
381
        );
382
383
        $result = $contentServiceMock->loadVersionInfo(
384
            new ContentInfo(['id' => 42]),
385
            7
386
        );
387
388
        $this->assertEquals('result', $result);
389
    }
390
391
    public function testLoadContent()
392
    {
393
        $repository = $this->getRepositoryMock();
394
        $contentService = $this->getPartlyMockedContentService(['internalLoadContent']);
395
        $content = $this->createMock(APIContent::class);
396
        $versionInfo = $this->createMock(APIVersionInfo::class);
397
        $content
398
            ->expects($this->once())
399
            ->method('getVersionInfo')
400
            ->will($this->returnValue($versionInfo));
401
        $versionInfo
402
            ->expects($this->once())
403
            ->method('isPublished')
404
            ->willReturn(true);
405
        $contentId = 123;
406
        $contentService
407
            ->expects($this->once())
408
            ->method('internalLoadContent')
409
            ->with($contentId)
410
            ->will($this->returnValue($content));
411
412
        $repository
413
            ->expects($this->once())
414
            ->method('canUser')
415
            ->with('content', 'read', $content)
416
            ->will($this->returnValue(true));
417
418
        $this->assertSame($content, $contentService->loadContent($contentId));
419
    }
420
421 View Code Duplication
    public function testLoadContentNonPublished()
422
    {
423
        $repository = $this->getRepositoryMock();
424
        $contentService = $this->getPartlyMockedContentService(['internalLoadContent']);
425
        $content = $this->createMock(APIContent::class);
426
        $versionInfo = $this
427
            ->getMockBuilder(APIVersionInfo::class)
428
            ->getMockForAbstractClass();
429
        $content
430
            ->expects($this->once())
431
            ->method('getVersionInfo')
432
            ->will($this->returnValue($versionInfo));
433
        $contentId = 123;
434
        $contentService
435
            ->expects($this->once())
436
            ->method('internalLoadContent')
437
            ->with($contentId)
438
            ->will($this->returnValue($content));
439
440
        $repository
441
            ->expects($this->exactly(2))
442
            ->method('canUser')
443
            ->will(
444
                $this->returnValueMap(
445
                    [
446
                        ['content', 'read', $content, null, true],
447
                        ['content', 'versionread', $content, null, true],
448
                    ]
449
                )
450
            );
451
452
        $this->assertSame($content, $contentService->loadContent($contentId));
453
    }
454
455
    public function testLoadContentUnauthorized()
456
    {
457
        $this->expectException(\eZ\Publish\Core\Base\Exceptions\UnauthorizedException::class);
458
459
        $repository = $this->getRepositoryMock();
460
        $contentService = $this->getPartlyMockedContentService(['internalLoadContent']);
461
        $content = $this->createMock(APIContent::class);
462
        $contentId = 123;
463
        $contentService
464
            ->expects($this->once())
465
            ->method('internalLoadContent')
466
            ->with($contentId)
467
            ->will($this->returnValue($content));
468
469
        $repository
470
            ->expects($this->once())
471
            ->method('canUser')
472
            ->with('content', 'read', $content)
473
            ->will($this->returnValue(false));
474
475
        $contentService->loadContent($contentId);
476
    }
477
478 View Code Duplication
    public function testLoadContentNotPublishedStatusUnauthorized()
479
    {
480
        $this->expectException(\eZ\Publish\Core\Base\Exceptions\UnauthorizedException::class);
481
482
        $repository = $this->getRepositoryMock();
483
        $contentService = $this->getPartlyMockedContentService(['internalLoadContent']);
484
        $content = $this->createMock(APIContent::class);
485
        $versionInfo = $this
486
            ->getMockBuilder(APIVersionInfo::class)
487
            ->getMockForAbstractClass();
488
        $content
489
            ->expects($this->once())
490
            ->method('getVersionInfo')
491
            ->will($this->returnValue($versionInfo));
492
        $contentId = 123;
493
        $contentService
494
            ->expects($this->once())
495
            ->method('internalLoadContent')
496
            ->with($contentId)
497
            ->will($this->returnValue($content));
498
499
        $repository
500
            ->expects($this->exactly(2))
501
            ->method('canUser')
502
            ->will(
503
                $this->returnValueMap(
504
                    [
505
                        ['content', 'read', $content, null, true],
506
                        ['content', 'versionread', $content, null, false],
507
                    ]
508
                )
509
            );
510
511
        $contentService->loadContent($contentId);
512
    }
513
514
    /**
515
     * @dataProvider internalLoadContentProvider
516
     */
517
    public function testInternalLoadContent($id, $languages, $versionNo, $isRemoteId, $useAlwaysAvailable)
518
    {
519
        $contentService = $this->getPartlyMockedContentService();
520
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandler */
521
        $contentHandler = $this->getPersistenceMock()->contentHandler();
522
        $realId = $id;
523
524
        if ($isRemoteId) {
525
            $realId = 123;
526
            $spiContentInfo = new SPIContentInfo(['currentVersionNo' => $versionNo ?: 7, 'id' => $realId]);
527
            $contentHandler
528
                ->expects($this->once())
529
                ->method('loadContentInfoByRemoteId')
530
                ->with($id)
531
                ->will($this->returnValue($spiContentInfo));
532
        } elseif (!empty($languages) && $useAlwaysAvailable) {
533
            $spiContentInfo = new SPIContentInfo(['alwaysAvailable' => false]);
534
            $contentHandler
535
                ->expects($this->once())
536
                ->method('loadContentInfo')
537
                ->with($id)
538
                ->will($this->returnValue($spiContentInfo));
539
        }
540
541
        $spiContent = new SPIContent([
542
            'versionInfo' => new VersionInfo([
543
                    'contentInfo' => new ContentInfo(['id' => 42, 'contentTypeId' => 123]),
544
            ]),
545
        ]);
546
        $contentHandler
547
            ->expects($this->once())
548
            ->method('load')
549
            ->with($realId, $versionNo, $languages)
550
            ->willReturn($spiContent);
551
552
        $content = $this->mockBuildContentDomainObject($spiContent, $languages);
553
554
        $this->assertSame(
555
            $content,
556
            $contentService->internalLoadContent($id, $languages, $versionNo, $isRemoteId, $useAlwaysAvailable)
557
        );
558
    }
559
560
    public function internalLoadContentProvider()
561
    {
562
        return [
563
            [123, null, null, false, false],
564
            [123, null, 456, false, false],
565
            [456, null, 123, false, true],
566
            [456, null, 2, false, false],
567
            [456, ['eng-GB'], 2, false, true],
568
            [456, ['eng-GB', 'fre-FR'], null, false, false],
569
            [456, ['eng-GB', 'fre-FR', 'nor-NO'], 2, false, false],
570
            // With remoteId
571
            [123, null, null, true, false],
572
            ['someRemoteId', null, 456, true, false],
573
            [456, null, 123, true, false],
574
            ['someRemoteId', null, 2, true, false],
575
            ['someRemoteId', ['eng-GB'], 2, true, false],
576
            [456, ['eng-GB', 'fre-FR'], null, true, false],
577
            ['someRemoteId', ['eng-GB', 'fre-FR', 'nor-NO'], 2, true, false],
578
        ];
579
    }
580
581
    public function testInternalLoadContentNotFound()
582
    {
583
        $this->expectException(\eZ\Publish\Core\Base\Exceptions\NotFoundException::class);
584
585
        $contentService = $this->getPartlyMockedContentService();
586
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandler */
587
        $contentHandler = $this->getPersistenceMock()->contentHandler();
588
        $id = 123;
589
        $versionNo = 7;
590
        $languages = null;
591
        $contentHandler
592
            ->expects($this->once())
593
            ->method('load')
594
            ->with($id, $versionNo, $languages)
595
            ->will(
596
                $this->throwException(
597
                    $this->createMock(APINotFoundException::class)
598
                )
599
            );
600
601
        $contentService->internalLoadContent($id, $languages, $versionNo);
602
    }
603
604
    /**
605
     * Test for the loadContentByContentInfo() method.
606
     *
607
     * @covers \eZ\Publish\Core\Repository\ContentService::loadContentByContentInfo
608
     */
609
    public function testLoadContentByContentInfo()
610
    {
611
        $contentServiceMock = $this->getPartlyMockedContentService(
612
            ['loadContent']
613
        );
614
        $contentServiceMock->expects(
615
            $this->once()
616
        )->method(
617
            'loadContent'
618
        )->with(
619
            $this->equalTo(42),
620
            $this->equalTo(['cro-HR']),
621
            $this->equalTo(7),
622
            $this->equalTo(false)
623
        )->will(
624
            $this->returnValue('result')
625
        );
626
627
        $result = $contentServiceMock->loadContentByContentInfo(
628
            new ContentInfo(['id' => 42]),
629
            ['cro-HR'],
630
            7
631
        );
632
633
        $this->assertEquals('result', $result);
634
    }
635
636
    /**
637
     * Test for the loadContentByVersionInfo() method.
638
     *
639
     * @covers \eZ\Publish\Core\Repository\ContentService::loadContentByVersionInfo
640
     */
641
    public function testLoadContentByVersionInfo()
642
    {
643
        $contentServiceMock = $this->getPartlyMockedContentService(
644
            ['loadContent']
645
        );
646
        $contentServiceMock->expects(
647
            $this->once()
648
        )->method(
649
            'loadContent'
650
        )->with(
651
            $this->equalTo(42),
652
            $this->equalTo(['cro-HR']),
653
            $this->equalTo(7),
654
            $this->equalTo(false)
655
        )->will(
656
            $this->returnValue('result')
657
        );
658
659
        $result = $contentServiceMock->loadContentByVersionInfo(
660
            new VersionInfo(
661
                [
662
                    'contentInfo' => new ContentInfo(['id' => 42]),
663
                    'versionNo' => 7,
664
                ]
665
            ),
666
            ['cro-HR']
667
        );
668
669
        $this->assertEquals('result', $result);
670
    }
671
672
    /**
673
     * Test for the deleteContent() method.
674
     *
675
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteContent
676
     */
677
    public function testDeleteContentThrowsUnauthorizedException()
678
    {
679
        $this->expectException(\eZ\Publish\Core\Base\Exceptions\UnauthorizedException::class);
680
681
        $repository = $this->getRepositoryMock();
682
        $contentService = $this->getPartlyMockedContentService(['internalLoadContentInfo']);
683
        $contentInfo = $this->createMock(APIContentInfo::class);
684
685
        $contentInfo->expects($this->any())
686
            ->method('__get')
687
            ->with('id')
688
            ->will($this->returnValue(42));
689
690
        $contentService->expects($this->once())
691
            ->method('internalLoadContentInfo')
692
            ->with(42)
693
            ->will($this->returnValue($contentInfo));
694
695
        $repository->expects($this->once())
696
            ->method('canUser')
697
            ->with('content', 'remove')
698
            ->will($this->returnValue(false));
699
700
        /* @var \eZ\Publish\API\Repository\Values\Content\ContentInfo $contentInfo */
701
        $contentService->deleteContent($contentInfo);
702
    }
703
704
    /**
705
     * Test for the deleteContent() method.
706
     *
707
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteContent
708
     */
709
    public function testDeleteContent()
710
    {
711
        $repository = $this->getRepositoryMock();
712
713
        $repository->expects($this->once())
714
            ->method('canUser')
715
            ->with('content', 'remove')
716
            ->will($this->returnValue(true));
717
718
        $contentService = $this->getPartlyMockedContentService(['internalLoadContentInfo']);
719
        /** @var \PHPUnit\Framework\MockObject\MockObject $urlAliasHandler */
720
        $urlAliasHandler = $this->getPersistenceMock()->urlAliasHandler();
721
        /** @var \PHPUnit\Framework\MockObject\MockObject $locationHandler */
722
        $locationHandler = $this->getPersistenceMock()->locationHandler();
723
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandler */
724
        $contentHandler = $this->getPersistenceMock()->contentHandler();
725
726
        $contentInfo = $this->createMock(APIContentInfo::class);
727
728
        $contentService->expects($this->once())
729
            ->method('internalLoadContentInfo')
730
            ->with(42)
731
            ->will($this->returnValue($contentInfo));
732
733
        $contentInfo->expects($this->any())
734
            ->method('__get')
735
            ->with('id')
736
            ->will($this->returnValue(42));
737
738
        $repository->expects($this->once())->method('beginTransaction');
739
740
        $spiLocations = [
741
            new SPILocation(['id' => 1]),
742
            new SPILocation(['id' => 2]),
743
        ];
744
        $locationHandler->expects($this->once())
745
            ->method('loadLocationsByContent')
746
            ->with(42)
747
            ->will($this->returnValue($spiLocations));
748
749
        $contentHandler->expects($this->once())
750
            ->method('deleteContent')
751
            ->with(42);
752
753
        foreach ($spiLocations as $index => $spiLocation) {
754
            $urlAliasHandler->expects($this->at($index))
755
                ->method('locationDeleted')
756
                ->with($spiLocation->id);
757
        }
758
759
        $repository->expects($this->once())->method('commit');
760
761
        /* @var \eZ\Publish\API\Repository\Values\Content\ContentInfo $contentInfo */
762
        $contentService->deleteContent($contentInfo);
763
    }
764
765
    /**
766
     * Test for the deleteContent() method.
767
     *
768
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteContent
769
     */
770
    public function testDeleteContentWithRollback()
771
    {
772
        $this->expectException(\Exception::class);
773
774
        $repository = $this->getRepositoryMock();
775
776
        $repository->expects($this->once())
777
            ->method('canUser')
778
            ->with('content', 'remove')
779
            ->will($this->returnValue(true));
780
781
        $contentService = $this->getPartlyMockedContentService(['internalLoadContentInfo']);
782
        /** @var \PHPUnit\Framework\MockObject\MockObject $locationHandler */
783
        $locationHandler = $this->getPersistenceMock()->locationHandler();
784
785
        $contentInfo = $this->createMock(APIContentInfo::class);
786
787
        $contentService->expects($this->once())
788
            ->method('internalLoadContentInfo')
789
            ->with(42)
790
            ->will($this->returnValue($contentInfo));
791
792
        $contentInfo->expects($this->any())
793
            ->method('__get')
794
            ->with('id')
795
            ->will($this->returnValue(42));
796
797
        $repository->expects($this->once())->method('beginTransaction');
798
799
        $locationHandler->expects($this->once())
800
            ->method('loadLocationsByContent')
801
            ->with(42)
802
            ->will($this->throwException(new \Exception()));
803
804
        $repository->expects($this->once())->method('rollback');
805
806
        /* @var \eZ\Publish\API\Repository\Values\Content\ContentInfo $contentInfo */
807
        $contentService->deleteContent($contentInfo);
808
    }
809
810
    /**
811
     * Test for the deleteVersion() method.
812
     *
813
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteVersion
814
     */
815
    public function testDeleteVersionThrowsBadStateExceptionLastVersion()
816
    {
817
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\BadStateException::class);
818
819
        $repository = $this->getRepositoryMock();
820
        $repository
821
            ->expects($this->once())
822
            ->method('canUser')
823
            ->with('content', 'versionremove')
824
            ->will($this->returnValue(true));
825
        $repository
826
            ->expects($this->never())
827
            ->method('beginTransaction');
828
829
        $contentService = $this->getPartlyMockedContentService();
830
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandler */
831
        $contentHandler = $this->getPersistenceMock()->contentHandler();
832
        $contentInfo = $this->createMock(APIContentInfo::class);
833
        $versionInfo = $this->createMock(APIVersionInfo::class);
834
835
        $contentInfo
836
            ->expects($this->any())
837
            ->method('__get')
838
            ->with('id')
839
            ->will($this->returnValue(42));
840
841
        $versionInfo
842
            ->expects($this->any())
843
            ->method('__get')
844
            ->will(
845
                $this->returnValueMap(
846
                    [
847
                        ['versionNo', 123],
848
                        ['contentInfo', $contentInfo],
849
                    ]
850
                )
851
            );
852
        $versionInfo
853
            ->expects($this->once())
854
            ->method('isPublished')
855
            ->willReturn(false);
856
857
        $contentHandler
858
            ->expects($this->once())
859
            ->method('listVersions')
860
            ->with(42)
861
            ->will($this->returnValue(['version']));
862
863
        /* @var \eZ\Publish\API\Repository\Values\Content\VersionInfo $versionInfo */
864
        $contentService->deleteVersion($versionInfo);
865
    }
866
867
    /**
868
     * Test for the createContent() method.
869
     *
870
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
871
     */
872 View Code Duplication
    public function testCreateContentThrowsInvalidArgumentExceptionMainLanguageCodeNotSet()
873
    {
874
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\InvalidArgumentException::class);
875
        $this->expectExceptionMessage('Argument \'$contentCreateStruct\' is invalid: \'mainLanguageCode\' property must be set');
876
877
        $mockedService = $this->getPartlyMockedContentService();
878
        $mockedService->createContent(new ContentCreateStruct(), []);
879
    }
880
881
    /**
882
     * Test for the createContent() method.
883
     *
884
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
885
     */
886 View Code Duplication
    public function testCreateContentThrowsInvalidArgumentExceptionContentTypeNotSet()
887
    {
888
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\InvalidArgumentException::class);
889
        $this->expectExceptionMessage('Argument \'$contentCreateStruct\' is invalid: \'contentType\' property must be set');
890
891
        $mockedService = $this->getPartlyMockedContentService();
892
        $mockedService->createContent(
893
            new ContentCreateStruct(['mainLanguageCode' => 'eng-US']),
894
            []
895
        );
896
    }
897
898
    /**
899
     * Test for the createContent() method.
900
     *
901
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
902
     */
903
    public function testCreateContentThrowsUnauthorizedException()
904
    {
905
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\UnauthorizedException::class);
906
907
        $repositoryMock = $this->getRepositoryMock();
908
        $mockedService = $this->getPartlyMockedContentService();
909
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
910
        $contentType = new ContentType(
911
            [
912
                'id' => 123,
913
                'fieldDefinitions' => [],
914
            ]
915
        );
916
        $contentCreateStruct = new ContentCreateStruct(
917
            [
918
                'ownerId' => 169,
919
                'alwaysAvailable' => false,
920
                'mainLanguageCode' => 'eng-US',
921
                'contentType' => $contentType,
922
            ]
923
        );
924
925
        $repositoryMock->expects($this->once())
926
            ->method('getCurrentUserReference')
927
            ->will($this->returnValue(new UserReference(169)));
928
929
        $contentTypeServiceMock->expects($this->once())
930
            ->method('loadContentType')
931
            ->with($this->equalTo(123))
932
            ->will($this->returnValue($contentType));
933
934
        $repositoryMock->expects($this->once())
935
            ->method('getContentTypeService')
936
            ->will($this->returnValue($contentTypeServiceMock));
937
938
        $repositoryMock->expects($this->once())
939
            ->method('canUser')
940
            ->with(
941
                $this->equalTo('content'),
942
                $this->equalTo('create'),
943
                $this->isInstanceOf(get_class($contentCreateStruct)),
944
                $this->equalTo([])
945
            )->will($this->returnValue(false));
946
947
        $mockedService->createContent(
948
            new ContentCreateStruct(
949
                [
950
                    'mainLanguageCode' => 'eng-US',
951
                    'contentType' => $contentType,
952
                ]
953
            ),
954
            []
955
        );
956
    }
957
958
    /**
959
     * Test for the createContent() method.
960
     *
961
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
962
     * @exceptionMessage Argument '$contentCreateStruct' is invalid: Another content with remoteId 'faraday' exists
963
     */
964
    public function testCreateContentThrowsInvalidArgumentExceptionDuplicateRemoteId()
965
    {
966
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\InvalidArgumentException::class);
967
968
        $repositoryMock = $this->getRepositoryMock();
969
        $mockedService = $this->getPartlyMockedContentService(['loadContentByRemoteId']);
970
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
971
        $contentType = new ContentType(
972
            [
973
                'id' => 123,
974
                'fieldDefinitions' => [],
975
            ]
976
        );
977
        $contentCreateStruct = new ContentCreateStruct(
978
            [
979
                'ownerId' => 169,
980
                'alwaysAvailable' => false,
981
                'remoteId' => 'faraday',
982
                'mainLanguageCode' => 'eng-US',
983
                'contentType' => $contentType,
984
            ]
985
        );
986
987
        $repositoryMock->expects($this->once())
988
            ->method('getCurrentUserReference')
989
            ->will($this->returnValue(new UserReference(169)));
990
991
        $contentTypeServiceMock->expects($this->once())
992
            ->method('loadContentType')
993
            ->with($this->equalTo(123))
994
            ->will($this->returnValue($contentType));
995
996
        $repositoryMock->expects($this->once())
997
            ->method('getContentTypeService')
998
            ->will($this->returnValue($contentTypeServiceMock));
999
1000
        $repositoryMock->expects($this->once())
1001
            ->method('canUser')
1002
            ->with(
1003
                $this->equalTo('content'),
1004
                $this->equalTo('create'),
1005
                $this->isInstanceOf(get_class($contentCreateStruct)),
1006
                $this->equalTo([])
1007
            )->will($this->returnValue(true));
1008
1009
        $mockedService->expects($this->once())
1010
            ->method('loadContentByRemoteId')
1011
            ->with($contentCreateStruct->remoteId)
1012
            ->will($this->returnValue('Hello...'));
1013
1014
        $mockedService->createContent(
1015
            new ContentCreateStruct(
1016
                [
1017
                    'remoteId' => 'faraday',
1018
                    'mainLanguageCode' => 'eng-US',
1019
                    'contentType' => $contentType,
1020
                ]
1021
            ),
1022
            []
1023
        );
1024
    }
1025
1026
    /**
1027
     * @param string $mainLanguageCode
1028
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $structFields
1029
     * @param \eZ\Publish\API\Repository\Values\ContentType\FieldDefinition[] $fieldDefinitions
1030
     *
1031
     * @return array
1032
     */
1033
    protected function mapStructFieldsForCreate($mainLanguageCode, $structFields, $fieldDefinitions)
1034
    {
1035
        $mappedFieldDefinitions = [];
1036
        foreach ($fieldDefinitions as $fieldDefinition) {
1037
            $mappedFieldDefinitions[$fieldDefinition->identifier] = $fieldDefinition;
1038
        }
1039
1040
        $mappedStructFields = [];
1041
        foreach ($structFields as $structField) {
1042
            if ($structField->languageCode === null) {
1043
                $languageCode = $mainLanguageCode;
1044
            } else {
1045
                $languageCode = $structField->languageCode;
1046
            }
1047
1048
            $mappedStructFields[$structField->fieldDefIdentifier][$languageCode] = (string)$structField->value;
1049
        }
1050
1051
        return $mappedStructFields;
1052
    }
1053
1054
    /**
1055
     * Returns full, possibly redundant array of field values, indexed by field definition
1056
     * identifier and language code.
1057
     *
1058
     * @throws \RuntimeException Method is intended to be used only with consistent fixtures
1059
     *
1060
     * @param string $mainLanguageCode
1061
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $structFields
1062
     * @param \eZ\Publish\API\Repository\Values\ContentType\FieldDefinition[] $fieldDefinitions
1063
     * @param array $languageCodes
1064
     *
1065
     * @return array
1066
     */
1067
    protected function determineValuesForCreate(
1068
        $mainLanguageCode,
1069
        array $structFields,
1070
        array $fieldDefinitions,
1071
        array $languageCodes
1072
    ) {
1073
        $mappedStructFields = $this->mapStructFieldsForCreate(
1074
            $mainLanguageCode,
1075
            $structFields,
1076
            $fieldDefinitions
1077
        );
1078
1079
        $values = [];
1080
1081
        foreach ($fieldDefinitions as $fieldDefinition) {
1082
            $identifier = $fieldDefinition->identifier;
1083
            foreach ($languageCodes as $languageCode) {
1084 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...
1085
                    if (isset($mappedStructFields[$identifier][$mainLanguageCode])) {
1086
                        $values[$identifier][$languageCode] = $mappedStructFields[$identifier][$mainLanguageCode];
1087
                    } else {
1088
                        $values[$identifier][$languageCode] = (string)$fieldDefinition->defaultValue;
1089
                    }
1090
                    continue;
1091
                }
1092
1093 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...
1094
                    $values[$identifier][$languageCode] = $mappedStructFields[$identifier][$languageCode];
1095
                    continue;
1096
                }
1097
1098
                $values[$identifier][$languageCode] = (string)$fieldDefinition->defaultValue;
1099
            }
1100
        }
1101
1102
        return $this->stubValues($values);
1103
    }
1104
1105
    /**
1106
     * @param string $mainLanguageCode
1107
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $structFields
1108
     *
1109
     * @return string[]
1110
     */
1111
    protected function determineLanguageCodesForCreate($mainLanguageCode, array $structFields)
1112
    {
1113
        $languageCodes = [];
1114
1115
        foreach ($structFields as $field) {
1116
            if ($field->languageCode === null || isset($languageCodes[$field->languageCode])) {
1117
                continue;
1118
            }
1119
1120
            $languageCodes[$field->languageCode] = true;
1121
        }
1122
1123
        $languageCodes[$mainLanguageCode] = true;
1124
1125
        return array_keys($languageCodes);
1126
    }
1127
1128
    /**
1129
     * Asserts that calling createContent() with given API field set causes calling
1130
     * Handler::createContent() with given SPI field set.
1131
     *
1132
     * @param string $mainLanguageCode
1133
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $structFields
1134
     * @param \eZ\Publish\SPI\Persistence\Content\Field[] $spiFields
1135
     * @param \eZ\Publish\API\Repository\Values\ContentType\FieldDefinition[] $fieldDefinitions
1136
     * @param \eZ\Publish\API\Repository\Values\Content\LocationCreateStruct[] $locationCreateStructs
1137
     * @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...
1138
     * @param bool $execute
1139
     *
1140
     * @return mixed
1141
     */
1142
    protected function assertForTestCreateContentNonRedundantFieldSet(
1143
        $mainLanguageCode,
1144
        array $structFields,
1145
        array $spiFields,
1146
        array $fieldDefinitions,
1147
        array $locationCreateStructs = [],
1148
        $withObjectStates = false,
1149
        $execute = true
1150
    ) {
1151
        $repositoryMock = $this->getRepositoryMock();
1152
        $mockedService = $this->getPartlyMockedContentService();
1153
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandlerMock */
1154
        $contentHandlerMock = $this->getPersistenceMock()->contentHandler();
1155
        /** @var \PHPUnit\Framework\MockObject\MockObject $languageHandlerMock */
1156
        $languageHandlerMock = $this->getPersistenceMock()->contentLanguageHandler();
1157
        /** @var \PHPUnit\Framework\MockObject\MockObject $objectStateHandlerMock */
1158
        $objectStateHandlerMock = $this->getPersistenceMock()->objectStateHandler();
1159
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
1160
        $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...
1161
        $domainMapperMock = $this->getDomainMapperMock();
1162
        $relationProcessorMock = $this->getRelationProcessorMock();
1163
        $nameSchemaServiceMock = $this->getNameSchemaServiceMock();
1164
        $fieldTypeMock = $this->createMock(SPIFieldType::class);
1165
        $languageCodes = $this->determineLanguageCodesForCreate($mainLanguageCode, $structFields);
1166
        $contentType = new ContentType(
1167
            [
1168
                'id' => 123,
1169
                'fieldDefinitions' => $fieldDefinitions,
1170
                'nameSchema' => '<nameSchema>',
1171
            ]
1172
        );
1173
        $contentCreateStruct = new ContentCreateStruct(
1174
            [
1175
                'fields' => $structFields,
1176
                'mainLanguageCode' => $mainLanguageCode,
1177
                'contentType' => $contentType,
1178
                'alwaysAvailable' => false,
1179
                'ownerId' => 169,
1180
                'sectionId' => 1,
1181
            ]
1182
        );
1183
1184
        $languageHandlerMock->expects($this->any())
1185
            ->method('loadByLanguageCode')
1186
            ->with($this->isType('string'))
1187
            ->will(
1188
                $this->returnCallback(
1189
                    function () {
1190
                        return new Language(['id' => 4242]);
1191
                    }
1192
                )
1193
            );
1194
1195
        $repositoryMock->expects($this->once())->method('beginTransaction');
1196
1197
        $contentTypeServiceMock->expects($this->once())
1198
            ->method('loadContentType')
1199
            ->with($this->equalTo($contentType->id))
1200
            ->will($this->returnValue($contentType));
1201
1202
        $repositoryMock->expects($this->once())
1203
            ->method('getContentTypeService')
1204
            ->will($this->returnValue($contentTypeServiceMock));
1205
1206
        $that = $this;
1207
        $repositoryMock->expects($this->once())
1208
            ->method('canUser')
1209
            ->with(
1210
                $this->equalTo('content'),
1211
                $this->equalTo('create'),
1212
                $this->isInstanceOf(APIContentCreateStruct::class),
1213
                $this->equalTo($locationCreateStructs)
1214
            )->will(
1215
                $this->returnCallback(
1216
                    function () use ($that, $contentCreateStruct) {
1217
                        $that->assertEquals($contentCreateStruct, func_get_arg(2));
1218
1219
                        return true;
1220
                    }
1221
                )
1222
            );
1223
1224
        $domainMapperMock->expects($this->once())
1225
            ->method('getUniqueHash')
1226
            ->with($this->isInstanceOf(APIContentCreateStruct::class))
1227
            ->will(
1228
                $this->returnCallback(
1229
                    function ($object) use ($that, $contentCreateStruct) {
1230
                        $that->assertEquals($contentCreateStruct, $object);
1231
1232
                        return 'hash';
1233
                    }
1234
                )
1235
            );
1236
1237
        $fieldTypeMock->expects($this->any())
1238
            ->method('acceptValue')
1239
            ->will(
1240
                $this->returnCallback(
1241
                    function ($valueString) {
1242
                        return new ValueStub($valueString);
1243
                    }
1244
                )
1245
            );
1246
1247
        $fieldTypeMock->expects($this->any())
1248
            ->method('toPersistenceValue')
1249
            ->will(
1250
                $this->returnCallback(
1251
                    function (ValueStub $value) {
1252
                        return (string)$value;
1253
                    }
1254
                )
1255
            );
1256
1257
        $emptyValue = self::EMPTY_FIELD_VALUE;
1258
        $fieldTypeMock->expects($this->any())
1259
            ->method('isEmptyValue')
1260
            ->will(
1261
                $this->returnCallback(
1262
                    function (ValueStub $value) use ($emptyValue) {
1263
                        return $emptyValue === (string)$value;
1264
                    }
1265
                )
1266
            );
1267
1268
        $fieldTypeMock->expects($this->any())
1269
            ->method('validate')
1270
            ->will($this->returnValue([]));
1271
1272
        $this->getFieldTypeRegistryMock()->expects($this->any())
1273
            ->method('getFieldType')
1274
            ->will($this->returnValue($fieldTypeMock));
1275
1276
        $relationProcessorMock
1277
            ->expects($this->exactly(count($fieldDefinitions) * count($languageCodes)))
1278
            ->method('appendFieldRelations')
1279
            ->with(
1280
                $this->isType('array'),
1281
                $this->isType('array'),
1282
                $this->isInstanceOf(SPIFieldType::class),
1283
                $this->isInstanceOf(Value::class),
1284
                $this->anything()
1285
            );
1286
1287
        $values = $this->determineValuesForCreate(
1288
            $mainLanguageCode,
1289
            $structFields,
1290
            $fieldDefinitions,
1291
            $languageCodes
1292
        );
1293
        $nameSchemaServiceMock->expects($this->once())
1294
            ->method('resolve')
1295
            ->with(
1296
                $this->equalTo($contentType->nameSchema),
1297
                $this->equalTo($contentType),
1298
                $this->equalTo($values),
1299
                $this->equalTo($languageCodes)
1300
            )->will($this->returnValue([]));
1301
1302
        $relationProcessorMock->expects($this->any())
1303
            ->method('processFieldRelations')
1304
            ->with(
1305
                $this->isType('array'),
1306
                $this->equalTo(42),
1307
                $this->isType('int'),
1308
                $this->equalTo($contentType),
1309
                $this->equalTo([])
1310
            );
1311
1312
        if (!$withObjectStates) {
1313
            $objectStateHandlerMock->expects($this->once())
1314
                ->method('loadAllGroups')
1315
                ->will($this->returnValue([]));
1316
        }
1317
1318
        if ($execute) {
1319
            $spiContentCreateStruct = new SPIContentCreateStruct(
1320
                [
1321
                    'name' => [],
1322
                    'typeId' => 123,
1323
                    'sectionId' => 1,
1324
                    'ownerId' => 169,
1325
                    'remoteId' => 'hash',
1326
                    'fields' => $spiFields,
1327
                    'modified' => time(),
1328
                    'initialLanguageId' => 4242,
1329
                ]
1330
            );
1331
            $spiContentCreateStruct2 = clone $spiContentCreateStruct;
1332
            ++$spiContentCreateStruct2->modified;
1333
1334
            $spiContent = new SPIContent(
1335
                [
1336
                    'versionInfo' => new SPIContent\VersionInfo(
1337
                        [
1338
                            'contentInfo' => new SPIContent\ContentInfo(['id' => 42]),
1339
                            'versionNo' => 7,
1340
                        ]
1341
                    ),
1342
                ]
1343
            );
1344
1345
            $contentHandlerMock->expects($this->once())
1346
                ->method('create')
1347
                ->with($this->logicalOr($spiContentCreateStruct, $spiContentCreateStruct2))
1348
                ->will($this->returnValue($spiContent));
1349
1350
            $repositoryMock->expects($this->once())->method('commit');
1351
            $domainMapperMock->expects($this->once())
1352
                ->method('buildContentDomainObject')
1353
                ->with(
1354
                    $this->isInstanceOf(SPIContent::class),
1355
                    $this->equalTo($contentType)
1356
                );
1357
1358
            $mockedService->createContent($contentCreateStruct, []);
1359
        }
1360
1361
        return $contentCreateStruct;
1362
    }
1363
1364
    public function providerForTestCreateContentNonRedundantFieldSet1()
1365
    {
1366
        $spiFields = [
1367
            new SPIField(
1368
                [
1369
                    'fieldDefinitionId' => 'fieldDefinitionId',
1370
                    'type' => 'fieldTypeIdentifier',
1371
                    'value' => 'newValue',
1372
                    'languageCode' => 'eng-US',
1373
                ]
1374
            ),
1375
        ];
1376
1377
        return [
1378
            // 0. Without language set
1379
            [
1380
                'eng-US',
1381
                [
1382
                    new Field(
1383
                        [
1384
                            'fieldDefIdentifier' => 'identifier',
1385
                            'value' => 'newValue',
1386
                            'languageCode' => 'eng-US',
1387
                        ]
1388
                    ),
1389
                ],
1390
                $spiFields,
1391
            ],
1392
            // 1. Without language set
1393
            [
1394
                'eng-US',
1395
                [
1396
                    new Field(
1397
                        [
1398
                            'fieldDefIdentifier' => 'identifier',
1399
                            'value' => 'newValue',
1400
                            'languageCode' => null,
1401
                        ]
1402
                    ),
1403
                ],
1404
                $spiFields,
1405
            ],
1406
        ];
1407
    }
1408
1409
    /**
1410
     * Test for the createContent() method.
1411
     *
1412
     * Testing the simplest use case.
1413
     *
1414
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
1415
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForCreate
1416
     * @covers \eZ\Publish\Core\Repository\ContentService::cloneField
1417
     * @covers \eZ\Publish\Core\Repository\ContentService::getDefaultObjectStates
1418
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
1419
     * @dataProvider providerForTestCreateContentNonRedundantFieldSet1
1420
     */
1421
    public function testCreateContentNonRedundantFieldSet1($mainLanguageCode, $structFields, $spiFields)
1422
    {
1423
        $fieldDefinitions = [
1424
            new FieldDefinition(
1425
                [
1426
                    'id' => 'fieldDefinitionId',
1427
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
1428
                    'isTranslatable' => false,
1429
                    'identifier' => 'identifier',
1430
                    'isRequired' => false,
1431
                    'defaultValue' => 'defaultValue',
1432
                ]
1433
            ),
1434
        ];
1435
1436
        $this->assertForTestCreateContentNonRedundantFieldSet(
1437
            $mainLanguageCode,
1438
            $structFields,
1439
            $spiFields,
1440
            $fieldDefinitions
1441
        );
1442
    }
1443
1444
    public function providerForTestCreateContentNonRedundantFieldSet2()
1445
    {
1446
        $spiFields = [
1447
            new SPIField(
1448
                [
1449
                    'fieldDefinitionId' => 'fieldDefinitionId1',
1450
                    'type' => 'fieldTypeIdentifier',
1451
                    'value' => 'newValue1',
1452
                    'languageCode' => 'eng-US',
1453
                ]
1454
            ),
1455
            new SPIField(
1456
                [
1457
                    'fieldDefinitionId' => 'fieldDefinitionId2',
1458
                    'type' => 'fieldTypeIdentifier',
1459
                    'value' => 'newValue2',
1460
                    'languageCode' => 'ger-DE',
1461
                ]
1462
            ),
1463
        ];
1464
1465
        return [
1466
            // 0. With language set
1467
            [
1468
                'eng-US',
1469
                [
1470
                    new Field(
1471
                        [
1472
                            'fieldDefIdentifier' => 'identifier1',
1473
                            'value' => 'newValue1',
1474
                            'languageCode' => 'eng-US',
1475
                        ]
1476
                    ),
1477
                    new Field(
1478
                        [
1479
                            'fieldDefIdentifier' => 'identifier2',
1480
                            'value' => 'newValue2',
1481
                            'languageCode' => 'ger-DE',
1482
                        ]
1483
                    ),
1484
                ],
1485
                $spiFields,
1486
            ],
1487
            // 1. Without language set
1488
            [
1489
                'eng-US',
1490
                [
1491
                    new Field(
1492
                        [
1493
                            'fieldDefIdentifier' => 'identifier1',
1494
                            'value' => 'newValue1',
1495
                            'languageCode' => null,
1496
                        ]
1497
                    ),
1498
                    new Field(
1499
                        [
1500
                            'fieldDefIdentifier' => 'identifier2',
1501
                            'value' => 'newValue2',
1502
                            'languageCode' => 'ger-DE',
1503
                        ]
1504
                    ),
1505
                ],
1506
                $spiFields,
1507
            ],
1508
        ];
1509
    }
1510
1511
    /**
1512
     * Test for the createContent() method.
1513
     *
1514
     * Testing multiple languages with multiple translatable fields with empty default value.
1515
     *
1516
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
1517
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForCreate
1518
     * @covers \eZ\Publish\Core\Repository\ContentService::cloneField
1519
     * @covers \eZ\Publish\Core\Repository\ContentService::getDefaultObjectStates
1520
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
1521
     * @dataProvider providerForTestCreateContentNonRedundantFieldSet2
1522
     */
1523
    public function testCreateContentNonRedundantFieldSet2($mainLanguageCode, $structFields, $spiFields)
1524
    {
1525
        $fieldDefinitions = [
1526
            new FieldDefinition(
1527
                [
1528
                    'id' => 'fieldDefinitionId1',
1529
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
1530
                    'isTranslatable' => true,
1531
                    'identifier' => 'identifier1',
1532
                    'isRequired' => false,
1533
                    'defaultValue' => self::EMPTY_FIELD_VALUE,
1534
                ]
1535
            ),
1536
            new FieldDefinition(
1537
                [
1538
                    'id' => 'fieldDefinitionId2',
1539
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
1540
                    'isTranslatable' => true,
1541
                    'identifier' => 'identifier2',
1542
                    'isRequired' => false,
1543
                    'defaultValue' => self::EMPTY_FIELD_VALUE,
1544
                ]
1545
            ),
1546
        ];
1547
1548
        $this->assertForTestCreateContentNonRedundantFieldSet(
1549
            $mainLanguageCode,
1550
            $structFields,
1551
            $spiFields,
1552
            $fieldDefinitions
1553
        );
1554
    }
1555
1556
    public function providerForTestCreateContentNonRedundantFieldSetComplex()
1557
    {
1558
        $spiFields0 = [
1559
            new SPIField(
1560
                [
1561
                    'fieldDefinitionId' => 'fieldDefinitionId2',
1562
                    'type' => 'fieldTypeIdentifier',
1563
                    'value' => 'defaultValue2',
1564
                    'languageCode' => 'eng-US',
1565
                ]
1566
            ),
1567
            new SPIField(
1568
                [
1569
                    'fieldDefinitionId' => 'fieldDefinitionId4',
1570
                    'type' => 'fieldTypeIdentifier',
1571
                    'value' => 'defaultValue4',
1572
                    'languageCode' => 'eng-US',
1573
                ]
1574
            ),
1575
        ];
1576
        $spiFields1 = [
1577
            new SPIField(
1578
                [
1579
                    'fieldDefinitionId' => 'fieldDefinitionId1',
1580
                    'type' => 'fieldTypeIdentifier',
1581
                    'value' => 'newValue1',
1582
                    'languageCode' => 'ger-DE',
1583
                ]
1584
            ),
1585
            new SPIField(
1586
                [
1587
                    'fieldDefinitionId' => 'fieldDefinitionId2',
1588
                    'type' => 'fieldTypeIdentifier',
1589
                    'value' => 'defaultValue2',
1590
                    'languageCode' => 'ger-DE',
1591
                ]
1592
            ),
1593
            new SPIField(
1594
                [
1595
                    'fieldDefinitionId' => 'fieldDefinitionId2',
1596
                    'type' => 'fieldTypeIdentifier',
1597
                    'value' => 'newValue2',
1598
                    'languageCode' => 'eng-US',
1599
                ]
1600
            ),
1601
            new SPIField(
1602
                [
1603
                    'fieldDefinitionId' => 'fieldDefinitionId4',
1604
                    'type' => 'fieldTypeIdentifier',
1605
                    'value' => 'newValue4',
1606
                    'languageCode' => 'eng-US',
1607
                ]
1608
            ),
1609
        ];
1610
1611
        return [
1612
            // 0. Creating by default values only
1613
            [
1614
                'eng-US',
1615
                [],
1616
                $spiFields0,
1617
            ],
1618
            // 1. Multiple languages with language set
1619
            [
1620
                'eng-US',
1621
                [
1622
                    new Field(
1623
                        [
1624
                            'fieldDefIdentifier' => 'identifier1',
1625
                            'value' => 'newValue1',
1626
                            'languageCode' => 'ger-DE',
1627
                        ]
1628
                    ),
1629
                    new Field(
1630
                        [
1631
                            'fieldDefIdentifier' => 'identifier2',
1632
                            'value' => 'newValue2',
1633
                            'languageCode' => 'eng-US',
1634
                        ]
1635
                    ),
1636
                    new Field(
1637
                        [
1638
                            'fieldDefIdentifier' => 'identifier4',
1639
                            'value' => 'newValue4',
1640
                            'languageCode' => 'eng-US',
1641
                        ]
1642
                    ),
1643
                ],
1644
                $spiFields1,
1645
            ],
1646
            // 2. Multiple languages without language set
1647
            [
1648
                'eng-US',
1649
                [
1650
                    new Field(
1651
                        [
1652
                            'fieldDefIdentifier' => 'identifier1',
1653
                            'value' => 'newValue1',
1654
                            'languageCode' => 'ger-DE',
1655
                        ]
1656
                    ),
1657
                    new Field(
1658
                        [
1659
                            'fieldDefIdentifier' => 'identifier2',
1660
                            'value' => 'newValue2',
1661
                            'languageCode' => null,
1662
                        ]
1663
                    ),
1664
                    new Field(
1665
                        [
1666
                            'fieldDefIdentifier' => 'identifier4',
1667
                            'value' => 'newValue4',
1668
                            'languageCode' => null,
1669
                        ]
1670
                    ),
1671
                ],
1672
                $spiFields1,
1673
            ],
1674
        ];
1675
    }
1676
1677
    protected function fixturesForTestCreateContentNonRedundantFieldSetComplex()
1678
    {
1679
        return [
1680
            new FieldDefinition(
1681
                [
1682
                    'id' => 'fieldDefinitionId1',
1683
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
1684
                    'isTranslatable' => true,
1685
                    'identifier' => 'identifier1',
1686
                    'isRequired' => false,
1687
                    'defaultValue' => self::EMPTY_FIELD_VALUE,
1688
                ]
1689
            ),
1690
            new FieldDefinition(
1691
                [
1692
                    'id' => 'fieldDefinitionId2',
1693
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
1694
                    'isTranslatable' => true,
1695
                    'identifier' => 'identifier2',
1696
                    'isRequired' => false,
1697
                    'defaultValue' => 'defaultValue2',
1698
                ]
1699
            ),
1700
            new FieldDefinition(
1701
                [
1702
                    'id' => 'fieldDefinitionId3',
1703
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
1704
                    'isTranslatable' => false,
1705
                    'identifier' => 'identifier3',
1706
                    'isRequired' => false,
1707
                    'defaultValue' => self::EMPTY_FIELD_VALUE,
1708
                ]
1709
            ),
1710
            new FieldDefinition(
1711
                [
1712
                    'id' => 'fieldDefinitionId4',
1713
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
1714
                    'isTranslatable' => false,
1715
                    'identifier' => 'identifier4',
1716
                    'isRequired' => false,
1717
                    'defaultValue' => 'defaultValue4',
1718
                ]
1719
            ),
1720
        ];
1721
    }
1722
1723
    /**
1724
     * Test for the createContent() method.
1725
     *
1726
     * Testing multiple languages with multiple translatable fields with empty default value.
1727
     *
1728
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
1729
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForCreate
1730
     * @covers \eZ\Publish\Core\Repository\ContentService::cloneField
1731
     * @covers \eZ\Publish\Core\Repository\ContentService::getDefaultObjectStates
1732
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
1733
     * @dataProvider providerForTestCreateContentNonRedundantFieldSetComplex
1734
     */
1735
    public function testCreateContentNonRedundantFieldSetComplex($mainLanguageCode, $structFields, $spiFields)
1736
    {
1737
        $fieldDefinitions = $this->fixturesForTestCreateContentNonRedundantFieldSetComplex();
1738
1739
        $this->assertForTestCreateContentNonRedundantFieldSet(
1740
            $mainLanguageCode,
1741
            $structFields,
1742
            $spiFields,
1743
            $fieldDefinitions
1744
        );
1745
    }
1746
1747 View Code Duplication
    public function providerForTestCreateContentWithInvalidLanguage()
1748
    {
1749
        return [
1750
            [
1751
                'eng-GB',
1752
                [
1753
                    new Field(
1754
                        [
1755
                            'fieldDefIdentifier' => 'identifier',
1756
                            'value' => 'newValue',
1757
                            'languageCode' => 'Klingon',
1758
                        ]
1759
                    ),
1760
                ],
1761
            ],
1762
            [
1763
                'Klingon',
1764
                [
1765
                    new Field(
1766
                        [
1767
                            'fieldDefIdentifier' => 'identifier',
1768
                            'value' => 'newValue',
1769
                            'languageCode' => 'eng-GB',
1770
                        ]
1771
                    ),
1772
                ],
1773
            ],
1774
        ];
1775
    }
1776
1777
    /**
1778
     * Test for the updateContent() method.
1779
     *
1780
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
1781
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
1782
     * @dataProvider providerForTestCreateContentWithInvalidLanguage
1783
     */
1784
    public function testCreateContentWithInvalidLanguage($mainLanguageCode, $structFields)
1785
    {
1786
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\NotFoundException::class);
1787
        $this->expectExceptionMessage('Could not find \'Language\' with identifier \'Klingon\'');
1788
1789
        $repositoryMock = $this->getRepositoryMock();
1790
        $mockedService = $this->getPartlyMockedContentService();
1791
        /** @var \PHPUnit\Framework\MockObject\MockObject $languageHandlerMock */
1792
        $languageHandlerMock = $this->getPersistenceMock()->contentLanguageHandler();
1793
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
1794
        $domainMapperMock = $this->getDomainMapperMock();
1795
        $contentType = new ContentType(
1796
            [
1797
                'id' => 123,
1798
                'fieldDefinitions' => [],
1799
            ]
1800
        );
1801
        $contentCreateStruct = new ContentCreateStruct(
1802
            [
1803
                'fields' => $structFields,
1804
                'mainLanguageCode' => $mainLanguageCode,
1805
                'contentType' => $contentType,
1806
                'alwaysAvailable' => false,
1807
                'ownerId' => 169,
1808
                'sectionId' => 1,
1809
            ]
1810
        );
1811
1812
        $languageHandlerMock->expects($this->any())
1813
            ->method('loadByLanguageCode')
1814
            ->with($this->isType('string'))
1815
            ->will(
1816
                $this->returnCallback(
1817 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...
1818
                        if ($languageCode === 'Klingon') {
1819
                            throw new NotFoundException('Language', 'Klingon');
1820
                        }
1821
1822
                        return new Language(['id' => 4242]);
1823
                    }
1824
                )
1825
            );
1826
1827
        $contentTypeServiceMock->expects($this->once())
1828
            ->method('loadContentType')
1829
            ->with($this->equalTo($contentType->id))
1830
            ->will($this->returnValue($contentType));
1831
1832
        $repositoryMock->expects($this->once())
1833
            ->method('getContentTypeService')
1834
            ->will($this->returnValue($contentTypeServiceMock));
1835
1836
        $that = $this;
1837
        $repositoryMock->expects($this->once())
1838
            ->method('canUser')
1839
            ->with(
1840
                $this->equalTo('content'),
1841
                $this->equalTo('create'),
1842
                $this->isInstanceOf(APIContentCreateStruct::class),
1843
                $this->equalTo([])
1844
            )->will(
1845
                $this->returnCallback(
1846
                    function () use ($that, $contentCreateStruct) {
1847
                        $that->assertEquals($contentCreateStruct, func_get_arg(2));
1848
1849
                        return true;
1850
                    }
1851
                )
1852
            );
1853
1854
        $domainMapperMock->expects($this->once())
1855
            ->method('getUniqueHash')
1856
            ->with($this->isInstanceOf(APIContentCreateStruct::class))
1857
            ->will(
1858
                $this->returnCallback(
1859
                    function ($object) use ($that, $contentCreateStruct) {
1860
                        $that->assertEquals($contentCreateStruct, $object);
1861
1862
                        return 'hash';
1863
                    }
1864
                )
1865
            );
1866
1867
        $mockedService->createContent($contentCreateStruct, []);
1868
    }
1869
1870
    protected function assertForCreateContentContentValidationException(
1871
        $mainLanguageCode,
1872
        $structFields,
1873
        $fieldDefinitions = []
1874
    ) {
1875
        $repositoryMock = $this->getRepositoryMock();
1876
        $mockedService = $this->getPartlyMockedContentService(['loadContentByRemoteId']);
1877
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
1878
        $contentType = new ContentType(
1879
            [
1880
                'id' => 123,
1881
                'fieldDefinitions' => $fieldDefinitions,
1882
            ]
1883
        );
1884
        $contentCreateStruct = new ContentCreateStruct(
1885
            [
1886
                'ownerId' => 169,
1887
                'alwaysAvailable' => false,
1888
                'remoteId' => 'faraday',
1889
                'mainLanguageCode' => $mainLanguageCode,
1890
                'fields' => $structFields,
1891
                'contentType' => $contentType,
1892
            ]
1893
        );
1894
1895
        $contentTypeServiceMock->expects($this->once())
1896
            ->method('loadContentType')
1897
            ->with($this->equalTo(123))
1898
            ->will($this->returnValue($contentType));
1899
1900
        $repositoryMock->expects($this->once())
1901
            ->method('getContentTypeService')
1902
            ->will($this->returnValue($contentTypeServiceMock));
1903
1904
        $repositoryMock->expects($this->once())
1905
            ->method('canUser')
1906
            ->with(
1907
                $this->equalTo('content'),
1908
                $this->equalTo('create'),
1909
                $this->isInstanceOf(get_class($contentCreateStruct)),
1910
                $this->equalTo([])
1911
            )->will($this->returnValue(true));
1912
1913
        $mockedService->expects($this->once())
1914
            ->method('loadContentByRemoteId')
1915
            ->with($contentCreateStruct->remoteId)
1916
            ->will(
1917
                $this->throwException(new NotFoundException('Content', 'faraday'))
1918
            );
1919
1920
        $mockedService->createContent($contentCreateStruct, []);
1921
    }
1922
1923 View Code Duplication
    public function providerForTestCreateContentThrowsContentValidationExceptionFieldDefinition()
1924
    {
1925
        return [
1926
            [
1927
                'eng-GB',
1928
                [
1929
                    new Field(
1930
                        [
1931
                            'fieldDefIdentifier' => 'identifier',
1932
                            'value' => 'newValue',
1933
                            'languageCode' => 'eng-GB',
1934
                        ]
1935
                    ),
1936
                ],
1937
            ],
1938
        ];
1939
    }
1940
1941
    /**
1942
     * Test for the createContent() method.
1943
     *
1944
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
1945
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForCreate
1946
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
1947
     * @dataProvider providerForTestCreateContentThrowsContentValidationExceptionFieldDefinition
1948
     */
1949
    public function testCreateContentThrowsContentValidationExceptionFieldDefinition($mainLanguageCode, $structFields)
1950
    {
1951
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\ContentValidationException::class);
1952
        $this->expectExceptionMessage('Field definition \'identifier\' does not exist in given ContentType');
1953
1954
        $this->assertForCreateContentContentValidationException(
1955
            $mainLanguageCode,
1956
            $structFields,
1957
            []
1958
        );
1959
    }
1960
1961 View Code Duplication
    public function providerForTestCreateContentThrowsContentValidationExceptionTranslation()
1962
    {
1963
        return [
1964
            [
1965
                'eng-GB',
1966
                [
1967
                    new Field(
1968
                        [
1969
                            'fieldDefIdentifier' => 'identifier',
1970
                            'value' => 'newValue',
1971
                            'languageCode' => 'eng-US',
1972
                        ]
1973
                    ),
1974
                ],
1975
            ],
1976
        ];
1977
    }
1978
1979
    /**
1980
     * Test for the createContent() method.
1981
     *
1982
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
1983
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForCreate
1984
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
1985
     * @dataProvider providerForTestCreateContentThrowsContentValidationExceptionTranslation
1986
     */
1987 View Code Duplication
    public function testCreateContentThrowsContentValidationExceptionTranslation($mainLanguageCode, $structFields)
1988
    {
1989
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\ContentValidationException::class);
1990
        $this->expectExceptionMessage('A value is set for non translatable field definition \'identifier\' with language \'eng-US\'');
1991
1992
        $fieldDefinitions = [
1993
            new FieldDefinition(
1994
                [
1995
                    'id' => 'fieldDefinitionId1',
1996
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
1997
                    'isTranslatable' => false,
1998
                    'identifier' => 'identifier',
1999
                    'isRequired' => false,
2000
                    'defaultValue' => self::EMPTY_FIELD_VALUE,
2001
                ]
2002
            ),
2003
        ];
2004
2005
        $this->assertForCreateContentContentValidationException(
2006
            $mainLanguageCode,
2007
            $structFields,
2008
            $fieldDefinitions
2009
        );
2010
    }
2011
2012
    /**
2013
     * Asserts behaviour necessary for testing ContentFieldValidationException because of required
2014
     * field being empty.
2015
     *
2016
     * @param string $mainLanguageCode
2017
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $structFields
2018
     * @param \eZ\Publish\API\Repository\Values\ContentType\FieldDefinition[] $fieldDefinitions
2019
     *
2020
     * @return mixed
2021
     */
2022
    protected function assertForTestCreateContentRequiredField(
2023
        $mainLanguageCode,
2024
        array $structFields,
2025
        array $fieldDefinitions
2026
    ) {
2027
        $repositoryMock = $this->getRepositoryMock();
2028
        /** @var \PHPUnit\Framework\MockObject\MockObject $languageHandlerMock */
2029
        $languageHandlerMock = $this->getPersistenceMock()->contentLanguageHandler();
2030
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
2031
        $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...
2032
        $domainMapperMock = $this->getDomainMapperMock();
2033
        $fieldTypeMock = $this->createMock(SPIFieldType::class);
2034
        $contentType = new ContentType(
2035
            [
2036
                'id' => 123,
2037
                'fieldDefinitions' => $fieldDefinitions,
2038
                'nameSchema' => '<nameSchema>',
2039
            ]
2040
        );
2041
        $contentCreateStruct = new ContentCreateStruct(
2042
            [
2043
                'fields' => $structFields,
2044
                'mainLanguageCode' => $mainLanguageCode,
2045
                'contentType' => $contentType,
2046
                'alwaysAvailable' => false,
2047
                'ownerId' => 169,
2048
                'sectionId' => 1,
2049
            ]
2050
        );
2051
2052
        $languageHandlerMock->expects($this->any())
2053
            ->method('loadByLanguageCode')
2054
            ->with($this->isType('string'))
2055
            ->will(
2056
                $this->returnCallback(
2057
                    function () {
2058
                        return new Language(['id' => 4242]);
2059
                    }
2060
                )
2061
            );
2062
2063
        $contentTypeServiceMock->expects($this->once())
2064
            ->method('loadContentType')
2065
            ->with($this->equalTo($contentType->id))
2066
            ->will($this->returnValue($contentType));
2067
2068
        $repositoryMock->expects($this->once())
2069
            ->method('getContentTypeService')
2070
            ->will($this->returnValue($contentTypeServiceMock));
2071
2072
        $that = $this;
2073
        $repositoryMock->expects($this->once())
2074
            ->method('canUser')
2075
            ->with(
2076
                $this->equalTo('content'),
2077
                $this->equalTo('create'),
2078
                $this->isInstanceOf(APIContentCreateStruct::class),
2079
                $this->equalTo([])
2080
            )->will(
2081
                $this->returnCallback(
2082
                    function () use ($that, $contentCreateStruct) {
2083
                        $that->assertEquals($contentCreateStruct, func_get_arg(2));
2084
2085
                        return true;
2086
                    }
2087
                )
2088
            );
2089
2090
        $domainMapperMock->expects($this->once())
2091
            ->method('getUniqueHash')
2092
            ->with($this->isInstanceOf(APIContentCreateStruct::class))
2093
            ->will(
2094
                $this->returnCallback(
2095
                    function ($object) use ($that, $contentCreateStruct) {
2096
                        $that->assertEquals($contentCreateStruct, $object);
2097
2098
                        return 'hash';
2099
                    }
2100
                )
2101
            );
2102
2103
        $fieldTypeMock->expects($this->any())
2104
            ->method('acceptValue')
2105
            ->will(
2106
                $this->returnCallback(
2107
                    function ($valueString) {
2108
                        return new ValueStub($valueString);
2109
                    }
2110
                )
2111
            );
2112
2113
        $emptyValue = self::EMPTY_FIELD_VALUE;
2114
        $fieldTypeMock->expects($this->any())
2115
            ->method('isEmptyValue')
2116
            ->will(
2117
                $this->returnCallback(
2118
                    function (ValueStub $value) use ($emptyValue) {
2119
                        return $emptyValue === (string)$value;
2120
                    }
2121
                )
2122
            );
2123
2124
        $fieldTypeMock->expects($this->any())
2125
            ->method('validate')
2126
            ->will($this->returnValue([]));
2127
2128
        $this->getFieldTypeRegistryMock()->expects($this->any())
2129
            ->method('getFieldType')
2130
            ->will($this->returnValue($fieldTypeMock));
2131
2132
        return $contentCreateStruct;
2133
    }
2134
2135 View Code Duplication
    public function providerForTestCreateContentThrowsContentValidationExceptionRequiredField()
2136
    {
2137
        return [
2138
            [
2139
                'eng-US',
2140
                [
2141
                    new Field(
2142
                        [
2143
                            'fieldDefIdentifier' => 'identifier',
2144
                            'value' => self::EMPTY_FIELD_VALUE,
2145
                            'languageCode' => null,
2146
                        ]
2147
                    ),
2148
                ],
2149
                'identifier',
2150
                'eng-US',
2151
            ],
2152
        ];
2153
    }
2154
2155
    /**
2156
     * Test for the createContent() method.
2157
     *
2158
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
2159
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForCreate
2160
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
2161
     * @dataProvider providerForTestCreateContentThrowsContentValidationExceptionRequiredField
2162
     */
2163
    public function testCreateContentRequiredField(
2164
        $mainLanguageCode,
2165
        $structFields,
2166
        $identifier,
2167
        $languageCode
2168
    ) {
2169
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\ContentFieldValidationException::class);
2170
2171
        $fieldDefinitions = [
2172
            new FieldDefinition(
2173
                [
2174
                    'id' => 'fieldDefinitionId',
2175
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
2176
                    'isTranslatable' => true,
2177
                    'identifier' => 'identifier',
2178
                    'isRequired' => true,
2179
                    'defaultValue' => 'defaultValue',
2180
                ]
2181
            ),
2182
        ];
2183
        $contentCreateStruct = $this->assertForTestCreateContentRequiredField(
2184
            $mainLanguageCode,
2185
            $structFields,
2186
            $fieldDefinitions
2187
        );
2188
2189
        $mockedService = $this->getPartlyMockedContentService();
2190
2191
        try {
2192
            $mockedService->createContent($contentCreateStruct, []);
2193
        } catch (ContentValidationException $e) {
2194
            $this->assertEquals(
2195
                "Value for required field definition '{$identifier}' with language '{$languageCode}' is empty",
2196
                $e->getMessage()
2197
            );
2198
2199
            throw $e;
2200
        }
2201
    }
2202
2203
    /**
2204
     * Asserts behaviour necessary for testing ContentFieldValidationException because of
2205
     * field not being valid.
2206
     *
2207
     * @param string $mainLanguageCode
2208
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $structFields
2209
     * @param \eZ\Publish\API\Repository\Values\ContentType\FieldDefinition[] $fieldDefinitions
2210
     *
2211
     * @return mixed
2212
     */
2213
    protected function assertForTestCreateContentThrowsContentFieldValidationException(
2214
        $mainLanguageCode,
2215
        array $structFields,
2216
        array $fieldDefinitions
2217
    ) {
2218
        $repositoryMock = $this->getRepositoryMock();
2219
        /** @var \PHPUnit\Framework\MockObject\MockObject $languageHandlerMock */
2220
        $languageHandlerMock = $this->getPersistenceMock()->contentLanguageHandler();
2221
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
2222
        $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...
2223
        $domainMapperMock = $this->getDomainMapperMock();
2224
        $relationProcessorMock = $this->getRelationProcessorMock();
2225
        $fieldTypeMock = $this->createMock(SPIFieldType::class);
2226
        $languageCodes = $this->determineLanguageCodesForCreate($mainLanguageCode, $structFields);
2227
        $contentType = new ContentType(
2228
            [
2229
                'id' => 123,
2230
                'fieldDefinitions' => $fieldDefinitions,
2231
                'nameSchema' => '<nameSchema>',
2232
            ]
2233
        );
2234
        $contentCreateStruct = new ContentCreateStruct(
2235
            [
2236
                'fields' => $structFields,
2237
                'mainLanguageCode' => $mainLanguageCode,
2238
                'contentType' => $contentType,
2239
                'alwaysAvailable' => false,
2240
                'ownerId' => 169,
2241
                'sectionId' => 1,
2242
            ]
2243
        );
2244
2245
        $languageHandlerMock->expects($this->any())
2246
            ->method('loadByLanguageCode')
2247
            ->with($this->isType('string'))
2248
            ->will(
2249
                $this->returnCallback(
2250
                    function () {
2251
                        return new Language(['id' => 4242]);
2252
                    }
2253
                )
2254
            );
2255
2256
        $contentTypeServiceMock->expects($this->once())
2257
            ->method('loadContentType')
2258
            ->with($this->equalTo($contentType->id))
2259
            ->will($this->returnValue($contentType));
2260
2261
        $repositoryMock->expects($this->once())
2262
            ->method('getContentTypeService')
2263
            ->will($this->returnValue($contentTypeServiceMock));
2264
2265
        $that = $this;
2266
        $repositoryMock->expects($this->once())
2267
            ->method('canUser')
2268
            ->with(
2269
                $this->equalTo('content'),
2270
                $this->equalTo('create'),
2271
                $this->isInstanceOf(APIContentCreateStruct::class),
2272
                $this->equalTo([])
2273
            )->will(
2274
                $this->returnCallback(
2275
                    function () use ($that, $contentCreateStruct) {
2276
                        $that->assertEquals($contentCreateStruct, func_get_arg(2));
2277
2278
                        return true;
2279
                    }
2280
                )
2281
            );
2282
2283
        $domainMapperMock->expects($this->once())
2284
            ->method('getUniqueHash')
2285
            ->with($this->isInstanceOf(APIContentCreateStruct::class))
2286
            ->will(
2287
                $this->returnCallback(
2288
                    function ($object) use ($that, $contentCreateStruct) {
2289
                        $that->assertEquals($contentCreateStruct, $object);
2290
2291
                        return 'hash';
2292
                    }
2293
                )
2294
            );
2295
2296
        $this->getFieldTypeRegistryMock()->expects($this->any())
2297
            ->method('getFieldType')
2298
            ->will($this->returnValue($fieldTypeMock));
2299
2300
        $relationProcessorMock
2301
            ->expects($this->any())
2302
            ->method('appendFieldRelations')
2303
            ->with(
2304
                $this->isType('array'),
2305
                $this->isType('array'),
2306
                $this->isInstanceOf(SPIFieldType::class),
2307
                $this->isInstanceOf(Value::class),
2308
                $this->anything()
2309
            );
2310
2311
        $fieldValues = $this->determineValuesForCreate(
2312
            $mainLanguageCode,
2313
            $structFields,
2314
            $fieldDefinitions,
2315
            $languageCodes
2316
        );
2317
        $allFieldErrors = [];
2318
        $validateCount = 0;
2319
        $emptyValue = self::EMPTY_FIELD_VALUE;
2320
        foreach ($contentType->getFieldDefinitions() as $fieldDefinition) {
2321
            foreach ($fieldValues[$fieldDefinition->identifier] as $languageCode => $value) {
2322
                $fieldTypeMock->expects($this->at($validateCount++))
2323
                    ->method('acceptValue')
2324
                    ->will(
2325
                        $this->returnCallback(
2326
                            function ($valueString) {
2327
                                return new ValueStub($valueString);
2328
                            }
2329
                        )
2330
                    );
2331
2332
                $fieldTypeMock->expects($this->at($validateCount++))
2333
                    ->method('isEmptyValue')
2334
                    ->will(
2335
                        $this->returnCallback(
2336
                            function (ValueStub $value) use ($emptyValue) {
2337
                                return $emptyValue === (string)$value;
2338
                            }
2339
                        )
2340
                    );
2341
2342
                if (self::EMPTY_FIELD_VALUE === (string)$value) {
2343
                    continue;
2344
                }
2345
2346
                $fieldTypeMock->expects($this->at($validateCount++))
2347
                    ->method('validate')
2348
                    ->with(
2349
                        $this->equalTo($fieldDefinition),
2350
                        $this->equalTo($value)
2351
                    )->will($this->returnArgument(1));
2352
2353
                $allFieldErrors[$fieldDefinition->id][$languageCode] = $value;
2354
            }
2355
        }
2356
2357
        return [$contentCreateStruct, $allFieldErrors];
2358
    }
2359
2360
    public function providerForTestCreateContentThrowsContentFieldValidationException()
2361
    {
2362
        return $this->providerForTestCreateContentNonRedundantFieldSetComplex();
2363
    }
2364
2365
    /**
2366
     * Test for the createContent() method.
2367
     *
2368
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
2369
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForCreate
2370
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
2371
     * @dataProvider providerForTestCreateContentThrowsContentFieldValidationException
2372
     */
2373 View Code Duplication
    public function testCreateContentThrowsContentFieldValidationException($mainLanguageCode, $structFields)
2374
    {
2375
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\ContentFieldValidationException::class);
2376
        $this->expectExceptionMessage('Content fields did not validate');
2377
2378
        $fieldDefinitions = $this->fixturesForTestCreateContentNonRedundantFieldSetComplex();
2379
        list($contentCreateStruct, $allFieldErrors) =
2380
            $this->assertForTestCreateContentThrowsContentFieldValidationException(
2381
                $mainLanguageCode,
2382
                $structFields,
2383
                $fieldDefinitions
2384
            );
2385
2386
        $mockedService = $this->getPartlyMockedContentService();
2387
2388
        try {
2389
            $mockedService->createContent($contentCreateStruct);
2390
        } catch (ContentFieldValidationException $e) {
2391
            $this->assertEquals($allFieldErrors, $e->getFieldErrors());
2392
            throw $e;
2393
        }
2394
    }
2395
2396
    /**
2397
     * Test for the createContent() method.
2398
     *
2399
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
2400
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForCreate
2401
     * @covers \eZ\Publish\Core\Repository\ContentService::buildSPILocationCreateStructs
2402
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
2403
     */
2404
    public function testCreateContentWithLocations()
2405
    {
2406
        $spiFields = [
2407
            new SPIField(
2408
                [
2409
                    'fieldDefinitionId' => 'fieldDefinitionId',
2410
                    'type' => 'fieldTypeIdentifier',
2411
                    'value' => 'defaultValue',
2412
                    'languageCode' => 'eng-US',
2413
                ]
2414
            ),
2415
        ];
2416
        $fieldDefinitions = [
2417
            new FieldDefinition(
2418
                [
2419
                    'id' => 'fieldDefinitionId',
2420
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
2421
                    'isTranslatable' => false,
2422
                    'identifier' => 'identifier',
2423
                    'isRequired' => false,
2424
                    'defaultValue' => 'defaultValue',
2425
                ]
2426
            ),
2427
        ];
2428
2429
        // Set up a simple case that will pass
2430
        $locationCreateStruct1 = new LocationCreateStruct(['parentLocationId' => 321]);
2431
        $locationCreateStruct2 = new LocationCreateStruct(['parentLocationId' => 654]);
2432
        $locationCreateStructs = [$locationCreateStruct1, $locationCreateStruct2];
2433
        $contentCreateStruct = $this->assertForTestCreateContentNonRedundantFieldSet(
2434
            'eng-US',
2435
            [],
2436
            $spiFields,
2437
            $fieldDefinitions,
2438
            $locationCreateStructs,
2439
            false,
2440
            // Do not execute
2441
            false
2442
        );
2443
2444
        $repositoryMock = $this->getRepositoryMock();
2445
        $mockedService = $this->getPartlyMockedContentService();
2446
        $locationServiceMock = $this->getLocationServiceMock();
2447
        /** @var \PHPUnit\Framework\MockObject\MockObject $handlerMock */
2448
        $handlerMock = $this->getPersistenceMock()->contentHandler();
2449
        $domainMapperMock = $this->getDomainMapperMock();
2450
        $spiLocationCreateStruct = new SPILocation\CreateStruct();
2451
        $parentLocation = new Location(['contentInfo' => new ContentInfo(['sectionId' => 1])]);
2452
2453
        $locationServiceMock->expects($this->at(0))
2454
            ->method('loadLocation')
2455
            ->with($this->equalTo(321))
2456
            ->will($this->returnValue($parentLocation));
2457
2458
        $locationServiceMock->expects($this->at(1))
2459
            ->method('loadLocation')
2460
            ->with($this->equalTo(654))
2461
            ->will($this->returnValue($parentLocation));
2462
2463
        $repositoryMock->expects($this->atLeastOnce())
2464
            ->method('getLocationService')
2465
            ->will($this->returnValue($locationServiceMock));
2466
2467
        $domainMapperMock->expects($this->at(1))
2468
            ->method('buildSPILocationCreateStruct')
2469
            ->with(
2470
                $this->equalTo($locationCreateStruct1),
2471
                $this->equalTo($parentLocation),
2472
                $this->equalTo(true),
2473
                $this->equalTo(null),
2474
                $this->equalTo(null)
2475
            )->will($this->returnValue($spiLocationCreateStruct));
2476
2477
        $domainMapperMock->expects($this->at(2))
2478
            ->method('buildSPILocationCreateStruct')
2479
            ->with(
2480
                $this->equalTo($locationCreateStruct2),
2481
                $this->equalTo($parentLocation),
2482
                $this->equalTo(false),
2483
                $this->equalTo(null),
2484
                $this->equalTo(null)
2485
            )->will($this->returnValue($spiLocationCreateStruct));
2486
2487
        $spiContentCreateStruct = new SPIContentCreateStruct(
2488
            [
2489
                'name' => [],
2490
                'typeId' => 123,
2491
                'sectionId' => 1,
2492
                'ownerId' => 169,
2493
                'remoteId' => 'hash',
2494
                'fields' => $spiFields,
2495
                'modified' => time(),
2496
                'initialLanguageId' => 4242,
2497
                'locations' => [$spiLocationCreateStruct, $spiLocationCreateStruct],
2498
            ]
2499
        );
2500
        $spiContentCreateStruct2 = clone $spiContentCreateStruct;
2501
        ++$spiContentCreateStruct2->modified;
2502
2503
        $spiContent = new SPIContent(
2504
            [
2505
                'versionInfo' => new SPIContent\VersionInfo(
2506
                    [
2507
                        'contentInfo' => new SPIContent\ContentInfo(['id' => 42]),
2508
                        'versionNo' => 7,
2509
                    ]
2510
                ),
2511
            ]
2512
        );
2513
2514
        $handlerMock->expects($this->once())
2515
            ->method('create')
2516
            ->with($this->logicalOr($spiContentCreateStruct, $spiContentCreateStruct2))
2517
            ->will($this->returnValue($spiContent));
2518
2519
        $domainMapperMock->expects($this->once())
2520
            ->method('buildContentDomainObject')
2521
            ->with(
2522
                $this->isInstanceOf(SPIContent::class),
2523
                $this->isInstanceOf(APIContentType::class)
2524
            );
2525
2526
        $repositoryMock->expects($this->once())->method('commit');
2527
2528
        // Execute
2529
        $mockedService->createContent($contentCreateStruct, $locationCreateStructs);
2530
    }
2531
2532
    /**
2533
     * Test for the createContent() method.
2534
     *
2535
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
2536
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForCreate
2537
     * @covers \eZ\Publish\Core\Repository\ContentService::buildSPILocationCreateStructs
2538
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
2539
     */
2540
    public function testCreateContentWithLocationsDuplicateUnderParent()
2541
    {
2542
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\InvalidArgumentException::class);
2543
        $this->expectExceptionMessage('Multiple LocationCreateStructs with the same parent Location \'321\' are given');
2544
2545
        $fieldDefinitions = [
2546
            new FieldDefinition(
2547
                [
2548
                    'id' => 'fieldDefinitionId',
2549
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
2550
                    'isTranslatable' => false,
2551
                    'identifier' => 'identifier',
2552
                    'isRequired' => false,
2553
                    'defaultValue' => 'defaultValue',
2554
                ]
2555
            ),
2556
        ];
2557
2558
        $repositoryMock = $this->getRepositoryMock();
2559
        $mockedService = $this->getPartlyMockedContentService();
2560
        $locationServiceMock = $this->getLocationServiceMock();
2561
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
2562
        $domainMapperMock = $this->getDomainMapperMock();
2563
        /** @var \PHPUnit\Framework\MockObject\MockObject $languageHandlerMock */
2564
        $languageHandlerMock = $this->getPersistenceMock()->contentLanguageHandler();
2565
        $spiLocationCreateStruct = new SPILocation\CreateStruct();
2566
        $parentLocation = new Location(['id' => 321]);
2567
        $locationCreateStruct = new LocationCreateStruct(['parentLocationId' => 321]);
2568
        $locationCreateStructs = [$locationCreateStruct, clone $locationCreateStruct];
2569
        $contentType = new ContentType(
2570
            [
2571
                'id' => 123,
2572
                'fieldDefinitions' => $fieldDefinitions,
2573
                'nameSchema' => '<nameSchema>',
2574
            ]
2575
        );
2576
        $contentCreateStruct = new ContentCreateStruct(
2577
            [
2578
                'fields' => [],
2579
                'mainLanguageCode' => 'eng-US',
2580
                'contentType' => $contentType,
2581
                'alwaysAvailable' => false,
2582
                'ownerId' => 169,
2583
                'sectionId' => 1,
2584
            ]
2585
        );
2586
2587
        $languageHandlerMock->expects($this->any())
2588
            ->method('loadByLanguageCode')
2589
            ->with($this->isType('string'))
2590
            ->will(
2591
                $this->returnCallback(
2592
                    function () {
2593
                        return new Language(['id' => 4242]);
2594
                    }
2595
                )
2596
            );
2597
2598
        $contentTypeServiceMock->expects($this->once())
2599
            ->method('loadContentType')
2600
            ->with($this->equalTo($contentType->id))
2601
            ->will($this->returnValue($contentType));
2602
2603
        $repositoryMock->expects($this->once())
2604
            ->method('getContentTypeService')
2605
            ->will($this->returnValue($contentTypeServiceMock));
2606
2607
        $that = $this;
2608
        $repositoryMock->expects($this->once())
2609
            ->method('canUser')
2610
            ->with(
2611
                $this->equalTo('content'),
2612
                $this->equalTo('create'),
2613
                $this->isInstanceOf(APIContentCreateStruct::class),
2614
                $this->equalTo($locationCreateStructs)
2615
            )->will(
2616
                $this->returnCallback(
2617
                    function () use ($that, $contentCreateStruct) {
2618
                        $that->assertEquals($contentCreateStruct, func_get_arg(2));
2619
2620
                        return true;
2621
                    }
2622
                )
2623
            );
2624
2625
        $domainMapperMock->expects($this->once())
2626
            ->method('getUniqueHash')
2627
            ->with($this->isInstanceOf(APIContentCreateStruct::class))
2628
            ->will(
2629
                $this->returnCallback(
2630
                    function ($object) use ($that, $contentCreateStruct) {
2631
                        $that->assertEquals($contentCreateStruct, $object);
2632
2633
                        return 'hash';
2634
                    }
2635
                )
2636
            );
2637
2638
        $locationServiceMock->expects($this->once())
2639
            ->method('loadLocation')
2640
            ->with($this->equalTo(321))
2641
            ->will($this->returnValue($parentLocation));
2642
2643
        $repositoryMock->expects($this->any())
2644
            ->method('getLocationService')
2645
            ->will($this->returnValue($locationServiceMock));
2646
2647
        $domainMapperMock->expects($this->any())
2648
            ->method('buildSPILocationCreateStruct')
2649
            ->with(
2650
                $this->equalTo($locationCreateStruct),
2651
                $this->equalTo($parentLocation),
2652
                $this->equalTo(true),
2653
                $this->equalTo(null),
2654
                $this->equalTo(null)
2655
            )->will($this->returnValue($spiLocationCreateStruct));
2656
2657
        $mockedService->createContent(
2658
            $contentCreateStruct,
2659
            $locationCreateStructs
2660
        );
2661
    }
2662
2663
    /**
2664
     * Test for the createContent() method.
2665
     *
2666
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
2667
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForCreate
2668
     * @covers \eZ\Publish\Core\Repository\ContentService::getDefaultObjectStates
2669
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
2670
     */
2671
    public function testCreateContentObjectStates()
2672
    {
2673
        $spiFields = [
2674
            new SPIField(
2675
                [
2676
                    'fieldDefinitionId' => 'fieldDefinitionId',
2677
                    'type' => 'fieldTypeIdentifier',
2678
                    'value' => 'defaultValue',
2679
                    'languageCode' => 'eng-US',
2680
                ]
2681
            ),
2682
        ];
2683
        $fieldDefinitions = [
2684
            new FieldDefinition(
2685
                [
2686
                    'id' => 'fieldDefinitionId',
2687
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
2688
                    'isTranslatable' => false,
2689
                    'identifier' => 'identifier',
2690
                    'isRequired' => false,
2691
                    'defaultValue' => 'defaultValue',
2692
                ]
2693
            ),
2694
        ];
2695
        $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...
2696
            new SPIObjectStateGroup(['id' => 10]),
2697
            new SPIObjectStateGroup(['id' => 20]),
2698
        ];
2699
2700
        // Set up a simple case that will pass
2701
        $contentCreateStruct = $this->assertForTestCreateContentNonRedundantFieldSet(
2702
            'eng-US',
2703
            [],
2704
            $spiFields,
2705
            $fieldDefinitions,
2706
            [],
2707
            true,
2708
            // Do not execute
2709
            false
2710
        );
2711
        $timestamp = time();
2712
        $contentCreateStruct->modificationDate = new \DateTime("@{$timestamp}");
2713
2714
        $repositoryMock = $this->getRepositoryMock();
2715
        $mockedService = $this->getPartlyMockedContentService();
2716
        /** @var \PHPUnit\Framework\MockObject\MockObject $handlerMock */
2717
        $handlerMock = $this->getPersistenceMock()->contentHandler();
2718
        $domainMapperMock = $this->getDomainMapperMock();
2719
2720
        $this->mockGetDefaultObjectStates();
2721
        $this->mockSetDefaultObjectStates();
2722
2723
        $spiContentCreateStruct = new SPIContentCreateStruct(
2724
            [
2725
                'name' => [],
2726
                'typeId' => 123,
2727
                'sectionId' => 1,
2728
                'ownerId' => 169,
2729
                'remoteId' => 'hash',
2730
                'fields' => $spiFields,
2731
                'modified' => $timestamp,
2732
                'initialLanguageId' => 4242,
2733
                'locations' => [],
2734
            ]
2735
        );
2736
        $spiContentCreateStruct2 = clone $spiContentCreateStruct;
2737
        ++$spiContentCreateStruct2->modified;
2738
2739
        $spiContent = new SPIContent(
2740
            [
2741
                'versionInfo' => new SPIContent\VersionInfo(
2742
                    [
2743
                        'contentInfo' => new SPIContent\ContentInfo(['id' => 42]),
2744
                        'versionNo' => 7,
2745
                    ]
2746
                ),
2747
            ]
2748
        );
2749
2750
        $handlerMock->expects($this->once())
2751
            ->method('create')
2752
            ->with($this->equalTo($spiContentCreateStruct))
2753
            ->will($this->returnValue($spiContent));
2754
2755
        $domainMapperMock->expects($this->once())
2756
            ->method('buildContentDomainObject')
2757
            ->with(
2758
                $this->isInstanceOf(SPIContent::class),
2759
                $this->isInstanceOf(APIContentType::class)
2760
            );
2761
2762
        $repositoryMock->expects($this->once())->method('commit');
2763
2764
        // Execute
2765
        $mockedService->createContent($contentCreateStruct, []);
2766
    }
2767
2768
    /**
2769
     * Test for the createContent() method.
2770
     *
2771
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
2772
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForCreate
2773
     * @covers \eZ\Publish\Core\Repository\ContentService::getDefaultObjectStates
2774
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
2775
     * @dataProvider providerForTestCreateContentThrowsContentValidationExceptionTranslation
2776
     */
2777
    public function testCreateContentWithRollback()
2778
    {
2779
        $this->expectException(\Exception::class);
2780
        $this->expectExceptionMessage('Store failed');
2781
2782
        $fieldDefinitions = [
2783
            new FieldDefinition(
2784
                [
2785
                    'id' => 'fieldDefinitionId',
2786
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
2787
                    'isTranslatable' => false,
2788
                    'identifier' => 'identifier',
2789
                    'isRequired' => false,
2790
                    'defaultValue' => 'defaultValue',
2791
                ]
2792
            ),
2793
        ];
2794
2795
        // Setup a simple case that will pass
2796
        $contentCreateStruct = $this->assertForTestCreateContentNonRedundantFieldSet(
2797
            'eng-US',
2798
            [],
2799
            [],
2800
            $fieldDefinitions,
2801
            [],
2802
            false,
2803
            // Do not execute test
2804
            false
2805
        );
2806
2807
        $repositoryMock = $this->getRepositoryMock();
2808
        $repositoryMock->expects($this->never())->method('commit');
2809
        $repositoryMock->expects($this->once())->method('rollback');
2810
2811
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandlerMock */
2812
        $contentHandlerMock = $this->getPersistenceMock()->contentHandler();
2813
        $contentHandlerMock->expects($this->once())
2814
            ->method('create')
2815
            ->with($this->anything())
2816
            ->will($this->throwException(new \Exception('Store failed')));
2817
2818
        // Execute
2819
        $this->partlyMockedContentService->createContent($contentCreateStruct, []);
2820
    }
2821
2822
    public function providerForTestUpdateContentThrowsBadStateException()
2823
    {
2824
        return [
2825
            [VersionInfo::STATUS_PUBLISHED],
2826
            [VersionInfo::STATUS_ARCHIVED],
2827
        ];
2828
    }
2829
2830
    /**
2831
     * Test for the updateContent() method.
2832
     *
2833
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContent
2834
     * @dataProvider providerForTestUpdateContentThrowsBadStateException
2835
     */
2836
    public function testUpdateContentThrowsBadStateException($status)
2837
    {
2838
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\BadStateException::class);
2839
2840
        $mockedService = $this->getPartlyMockedContentService(['loadContent']);
2841
        $contentUpdateStruct = new ContentUpdateStruct();
2842
        $versionInfo = new VersionInfo(
2843
            [
2844
                'contentInfo' => new ContentInfo(['id' => 42]),
2845
                'versionNo' => 7,
2846
                'status' => $status,
2847
            ]
2848
        );
2849
        $content = new Content(
2850
            [
2851
                'versionInfo' => $versionInfo,
2852
                'internalFields' => [],
2853
            ]
2854
        );
2855
2856
        $mockedService->expects($this->once())
2857
            ->method('loadContent')
2858
            ->with(
2859
                $this->equalTo(42),
2860
                $this->equalTo(null),
2861
                $this->equalTo(7)
2862
            )->will(
2863
                $this->returnValue($content)
2864
            );
2865
2866
        $mockedService->updateContent($versionInfo, $contentUpdateStruct);
2867
    }
2868
2869
    /**
2870
     * Test for the updateContent() method.
2871
     *
2872
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContent
2873
     */
2874
    public function testUpdateContentThrowsUnauthorizedException()
2875
    {
2876
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\UnauthorizedException::class);
2877
2878
        $permissionResolverMock = $this->getPermissionResolverMock();
2879
        $mockedService = $this->getPartlyMockedContentService(['loadContent']);
2880
        $contentUpdateStruct = new ContentUpdateStruct();
2881
        $versionInfo = new VersionInfo(
2882
            [
2883
                'contentInfo' => new ContentInfo(['id' => 42]),
2884
                'versionNo' => 7,
2885
                'status' => VersionInfo::STATUS_DRAFT,
2886
            ]
2887
        );
2888
        $content = new Content(
2889
            [
2890
                'versionInfo' => $versionInfo,
2891
                'internalFields' => [],
2892
            ]
2893
        );
2894
2895
        $mockedService->expects($this->once())
2896
            ->method('loadContent')
2897
            ->with(
2898
                $this->equalTo(42),
2899
                $this->equalTo(null),
2900
                $this->equalTo(7)
2901
            )->will(
2902
                $this->returnValue($content)
2903
            );
2904
2905
        $permissionResolverMock->expects($this->once())
2906
            ->method('canUser')
2907
            ->with(
2908
                $this->equalTo('content'),
2909
                $this->equalTo('edit'),
2910
                $this->equalTo($content),
2911
                $this->isType('array')
2912
            )->will($this->returnValue(false));
2913
2914
        $mockedService->updateContent($versionInfo, $contentUpdateStruct);
2915
    }
2916
2917
    /**
2918
     * @param string $initialLanguageCode
2919
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $structFields
2920
     * @param string[] $existingLanguages
2921
     *
2922
     * @return string[]
2923
     */
2924
    protected function determineLanguageCodesForUpdate($initialLanguageCode, array $structFields, $existingLanguages)
2925
    {
2926
        $languageCodes = array_fill_keys($existingLanguages, true);
2927
        if ($initialLanguageCode !== null) {
2928
            $languageCodes[$initialLanguageCode] = true;
2929
        }
2930
2931
        foreach ($structFields as $field) {
2932
            if ($field->languageCode === null || isset($languageCodes[$field->languageCode])) {
2933
                continue;
2934
            }
2935
2936
            $languageCodes[$field->languageCode] = true;
2937
        }
2938
2939
        return array_keys($languageCodes);
2940
    }
2941
2942
    /**
2943
     * @param string $initialLanguageCode
2944
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $structFields
2945
     * @param string $mainLanguageCode
2946
     * @param \eZ\Publish\API\Repository\Values\ContentType\FieldDefinition[] $fieldDefinitions
2947
     *
2948
     * @return array
2949
     */
2950
    protected function mapStructFieldsForUpdate($initialLanguageCode, $structFields, $mainLanguageCode, $fieldDefinitions)
2951
    {
2952
        $initialLanguageCode = $initialLanguageCode ?: $mainLanguageCode;
2953
2954
        $mappedFieldDefinitions = [];
2955
        foreach ($fieldDefinitions as $fieldDefinition) {
2956
            $mappedFieldDefinitions[$fieldDefinition->identifier] = $fieldDefinition;
2957
        }
2958
2959
        $mappedStructFields = [];
2960
        foreach ($structFields as $structField) {
2961
            $identifier = $structField->fieldDefIdentifier;
2962
2963
            if ($structField->languageCode !== null) {
2964
                $languageCode = $structField->languageCode;
2965
            } elseif ($mappedFieldDefinitions[$identifier]->isTranslatable) {
2966
                $languageCode = $initialLanguageCode;
2967
            } else {
2968
                $languageCode = $mainLanguageCode;
2969
            }
2970
2971
            $mappedStructFields[$identifier][$languageCode] = (string)$structField->value;
2972
        }
2973
2974
        return $mappedStructFields;
2975
    }
2976
2977
    /**
2978
     * Returns full, possibly redundant array of field values, indexed by field definition
2979
     * identifier and language code.
2980
     *
2981
     * @param string $initialLanguageCode
2982
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $structFields
2983
     * @param \eZ\Publish\Core\Repository\Values\Content\Content $content
2984
     * @param \eZ\Publish\API\Repository\Values\ContentType\FieldDefinition[] $fieldDefinitions
2985
     * @param array $languageCodes
2986
     *
2987
     * @return array
2988
     */
2989
    protected function determineValuesForUpdate(
2990
        $initialLanguageCode,
2991
        array $structFields,
2992
        Content $content,
2993
        array $fieldDefinitions,
2994
        array $languageCodes
2995
    ) {
2996
        $mainLanguageCode = $content->versionInfo->contentInfo->mainLanguageCode;
2997
2998
        $mappedStructFields = $this->mapStructFieldsForUpdate(
2999
            $initialLanguageCode,
3000
            $structFields,
3001
            $mainLanguageCode,
3002
            $fieldDefinitions
3003
        );
3004
3005
        $values = [];
3006
3007
        foreach ($fieldDefinitions as $fieldDefinition) {
3008
            $identifier = $fieldDefinition->identifier;
3009
            foreach ($languageCodes as $languageCode) {
3010 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...
3011
                    if (isset($mappedStructFields[$identifier][$mainLanguageCode])) {
3012
                        $values[$identifier][$languageCode] = $mappedStructFields[$identifier][$mainLanguageCode];
3013
                    } else {
3014
                        $values[$identifier][$languageCode] = (string)$content->fields[$identifier][$mainLanguageCode];
3015
                    }
3016
                    continue;
3017
                }
3018
3019 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...
3020
                    $values[$identifier][$languageCode] = $mappedStructFields[$identifier][$languageCode];
3021
                    continue;
3022
                }
3023
3024
                if (isset($content->fields[$identifier][$languageCode])) {
3025
                    $values[$identifier][$languageCode] = (string)$content->fields[$identifier][$languageCode];
3026
                    continue;
3027
                }
3028
3029
                $values[$identifier][$languageCode] = (string)$fieldDefinition->defaultValue;
3030
            }
3031
        }
3032
3033
        return $this->stubValues($values);
3034
    }
3035
3036
    protected function stubValues(array $fieldValues)
3037
    {
3038
        foreach ($fieldValues as &$languageValues) {
3039
            foreach ($languageValues as &$value) {
3040
                $value = new ValueStub($value);
3041
            }
3042
        }
3043
3044
        return $fieldValues;
3045
    }
3046
3047
    /**
3048
     * Asserts that calling updateContent() with given API field set causes calling
3049
     * Handler::updateContent() with given SPI field set.
3050
     *
3051
     * @param string $initialLanguageCode
3052
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $structFields
3053
     * @param \eZ\Publish\SPI\Persistence\Content\Field[] $spiFields
3054
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $existingFields
3055
     * @param \eZ\Publish\API\Repository\Values\ContentType\FieldDefinition[] $fieldDefinitions
3056
     * @param bool $execute
3057
     *
3058
     * @return mixed
3059
     */
3060
    protected function assertForTestUpdateContentNonRedundantFieldSet(
3061
        $initialLanguageCode,
3062
        array $structFields,
3063
        array $spiFields,
3064
        array $existingFields,
3065
        array $fieldDefinitions,
3066
        $execute = true
3067
    ) {
3068
        $repositoryMock = $this->getRepositoryMock();
3069
        $permissionResolverMock = $this->getPermissionResolverMock();
3070
        $mockedService = $this->getPartlyMockedContentService(['loadContent', 'loadRelations']);
3071
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandlerMock */
3072
        $contentHandlerMock = $this->getPersistenceMock()->contentHandler();
3073
        /** @var \PHPUnit\Framework\MockObject\MockObject $languageHandlerMock */
3074
        $languageHandlerMock = $this->getPersistenceMock()->contentLanguageHandler();
3075
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
3076
        $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...
3077
        $domainMapperMock = $this->getDomainMapperMock();
3078
        $relationProcessorMock = $this->getRelationProcessorMock();
3079
        $nameSchemaServiceMock = $this->getNameSchemaServiceMock();
3080
        $fieldTypeMock = $this->createMock(SPIFieldType::class);
3081
        $existingLanguageCodes = array_map(
3082
            function (Field $field) {
3083
                return $field->languageCode;
3084
            },
3085
            $existingFields
3086
        );
3087
        $languageCodes = $this->determineLanguageCodesForUpdate(
3088
            $initialLanguageCode,
3089
            $structFields,
3090
            $existingLanguageCodes
3091
        );
3092
        $versionInfo = new VersionInfo(
3093
            [
3094
                'contentInfo' => new ContentInfo(
3095
                    [
3096
                        'id' => 42,
3097
                        'contentTypeId' => 24,
3098
                        'mainLanguageCode' => 'eng-GB',
3099
                    ]
3100
                ),
3101
                'versionNo' => 7,
3102
                'languageCodes' => $existingLanguageCodes,
3103
                'status' => VersionInfo::STATUS_DRAFT,
3104
            ]
3105
        );
3106
        $content = new Content(
3107
            [
3108
                'versionInfo' => $versionInfo,
3109
                'internalFields' => $existingFields,
3110
            ]
3111
        );
3112
        $contentType = new ContentType(['fieldDefinitions' => $fieldDefinitions]);
3113
3114
        $languageHandlerMock->expects($this->any())
3115
            ->method('loadByLanguageCode')
3116
            ->with($this->isType('string'))
3117
            ->will(
3118
                $this->returnCallback(
3119
                    function () {
3120
                        return new Language(['id' => 4242]);
3121
                    }
3122
                )
3123
            );
3124
3125
        $mockedService->expects($this->once())
3126
            ->method('loadContent')
3127
            ->with(
3128
                $this->equalTo(42),
3129
                $this->equalTo(null),
3130
                $this->equalTo(7)
3131
            )->will(
3132
                $this->returnValue($content)
3133
            );
3134
3135
        $repositoryMock->expects($this->once())->method('beginTransaction');
3136
3137
        $permissionResolverMock->expects($this->once())
3138
            ->method('canUser')
3139
            ->with(
3140
                $this->equalTo('content'),
3141
                $this->equalTo('edit'),
3142
                $this->equalTo($content),
3143
                $this->isType('array')
3144
            )->will($this->returnValue(true));
3145
3146
        $contentTypeServiceMock->expects($this->once())
3147
            ->method('loadContentType')
3148
            ->with($this->equalTo(24))
3149
            ->will($this->returnValue($contentType));
3150
3151
        $repositoryMock->expects($this->once())
3152
            ->method('getContentTypeService')
3153
            ->will($this->returnValue($contentTypeServiceMock));
3154
3155
        $repositoryMock->expects($this->once())
3156
            ->method('getCurrentUserReference')
3157
            ->will($this->returnValue(new UserReference(169)));
3158
3159
        $fieldTypeMock->expects($this->any())
3160
            ->method('acceptValue')
3161
            ->will(
3162
                $this->returnCallback(
3163
                    function ($valueString) {
3164
                        return new ValueStub($valueString);
3165
                    }
3166
                )
3167
            );
3168
3169
        $emptyValue = self::EMPTY_FIELD_VALUE;
3170
        $fieldTypeMock->expects($this->any())
3171
            ->method('toPersistenceValue')
3172
            ->will(
3173
                $this->returnCallback(
3174
                    function (ValueStub $value) {
3175
                        return (string)$value;
3176
                    }
3177
                )
3178
            );
3179
3180
        $fieldTypeMock->expects($this->any())
3181
            ->method('isEmptyValue')
3182
            ->will(
3183
                $this->returnCallback(
3184
                    function (ValueStub $value) use ($emptyValue) {
3185
                        return $emptyValue === (string)$value;
3186
                    }
3187
                )
3188
            );
3189
3190
        $fieldTypeMock->expects($this->any())
3191
            ->method('validate')
3192
            ->will($this->returnValue([]));
3193
3194
        $this->getFieldTypeRegistryMock()->expects($this->any())
3195
            ->method('getFieldType')
3196
            ->will($this->returnValue($fieldTypeMock));
3197
3198
        $relationProcessorMock
3199
            ->expects($this->exactly(count($fieldDefinitions) * count($languageCodes)))
3200
            ->method('appendFieldRelations')
3201
            ->with(
3202
                $this->isType('array'),
3203
                $this->isType('array'),
3204
                $this->isInstanceOf(SPIFieldType::class),
3205
                $this->isInstanceOf(Value::class),
3206
                $this->anything()
3207
            );
3208
3209
        $values = $this->determineValuesForUpdate(
3210
            $initialLanguageCode,
3211
            $structFields,
3212
            $content,
3213
            $fieldDefinitions,
3214
            $languageCodes
3215
        );
3216
        $nameSchemaServiceMock->expects($this->once())
3217
            ->method('resolveNameSchema')
3218
            ->with(
3219
                $this->equalTo($content),
3220
                $this->equalTo($values),
3221
                $this->equalTo($languageCodes)
3222
            )->will($this->returnValue([]));
3223
3224
        $existingRelations = ['RELATIONS!!!'];
3225
        $mockedService->expects($this->once())
3226
            ->method('loadRelations')
3227
            ->with($content->versionInfo)
3228
            ->will($this->returnValue($existingRelations));
3229
        $relationProcessorMock->expects($this->any())
3230
            ->method('processFieldRelations')
3231
            ->with(
3232
                $this->isType('array'),
3233
                $this->equalTo(42),
3234
                $this->isType('int'),
3235
                $this->equalTo($contentType),
3236
                $this->equalTo($existingRelations)
3237
            );
3238
3239
        $contentUpdateStruct = new ContentUpdateStruct(
3240
            [
3241
                'fields' => $structFields,
3242
                'initialLanguageCode' => $initialLanguageCode,
3243
            ]
3244
        );
3245
3246
        if ($execute) {
3247
            $spiContentUpdateStruct = new SPIContentUpdateStruct(
3248
                [
3249
                    'creatorId' => 169,
3250
                    'fields' => $spiFields,
3251
                    'modificationDate' => time(),
3252
                    'initialLanguageId' => 4242,
3253
                ]
3254
            );
3255
3256
            // During code coverage runs, timestamp might differ 1-3 seconds
3257
            $spiContentUpdateStructTs1 = clone $spiContentUpdateStruct;
3258
            ++$spiContentUpdateStructTs1->modificationDate;
3259
3260
            $spiContentUpdateStructTs2 = clone $spiContentUpdateStructTs1;
3261
            ++$spiContentUpdateStructTs2->modificationDate;
3262
3263
            $spiContentUpdateStructTs3 = clone $spiContentUpdateStructTs2;
3264
            ++$spiContentUpdateStructTs3->modificationDate;
3265
3266
            $spiContent = new SPIContent(
3267
                [
3268
                    'versionInfo' => new SPIContent\VersionInfo(
3269
                        [
3270
                            'contentInfo' => new SPIContent\ContentInfo(['id' => 42]),
3271
                            'versionNo' => 7,
3272
                        ]
3273
                    ),
3274
                ]
3275
            );
3276
3277
            $contentHandlerMock->expects($this->once())
3278
                ->method('updateContent')
3279
                ->with(
3280
                    42,
3281
                    7,
3282
                    $this->logicalOr($spiContentUpdateStruct, $spiContentUpdateStructTs1, $spiContentUpdateStructTs2, $spiContentUpdateStructTs3)
3283
                )
3284
                ->will($this->returnValue($spiContent));
3285
3286
            $repositoryMock->expects($this->once())->method('commit');
3287
            $domainMapperMock->expects($this->once())
3288
                ->method('buildContentDomainObject')
3289
                ->with(
3290
                    $this->isInstanceOf(SPIContent::class),
3291
                    $this->isInstanceOf(APIContentType::class)
3292
                );
3293
3294
            $mockedService->updateContent($content->versionInfo, $contentUpdateStruct);
3295
        }
3296
3297
        return [$content->versionInfo, $contentUpdateStruct];
3298
    }
3299
3300
    public function providerForTestUpdateContentNonRedundantFieldSet1()
3301
    {
3302
        $spiFields = [
3303
            new SPIField(
3304
                [
3305
                    'id' => '100',
3306
                    'fieldDefinitionId' => 'fieldDefinitionId',
3307
                    'type' => 'fieldTypeIdentifier',
3308
                    'value' => 'newValue',
3309
                    'languageCode' => 'eng-GB',
3310
                    'versionNo' => 7,
3311
                ]
3312
            ),
3313
        ];
3314
3315
        return [
3316
            // With languages set
3317
            [
3318
                'eng-GB',
3319
                [
3320
                    new Field(
3321
                        [
3322
                            'fieldDefIdentifier' => 'identifier',
3323
                            'value' => 'newValue',
3324
                            'languageCode' => 'eng-GB',
3325
                        ]
3326
                    ),
3327
                ],
3328
                $spiFields,
3329
            ],
3330
            // Without languages set
3331
            [
3332
                null,
3333
                [
3334
                    new Field(
3335
                        [
3336
                            'fieldDefIdentifier' => 'identifier',
3337
                            'value' => 'newValue',
3338
                            'languageCode' => null,
3339
                        ]
3340
                    ),
3341
                ],
3342
                $spiFields,
3343
            ],
3344
            // Adding new language without fields
3345
            [
3346
                'eng-US',
3347
                [],
3348
                [],
3349
            ],
3350
        ];
3351
    }
3352
3353
    /**
3354
     * Test for the updateContent() method.
3355
     *
3356
     * Testing the simplest use case.
3357
     *
3358
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForUpdate
3359
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForUpdate
3360
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContent
3361
     * @dataProvider providerForTestUpdateContentNonRedundantFieldSet1
3362
     */
3363 View Code Duplication
    public function testUpdateContentNonRedundantFieldSet1($initialLanguageCode, $structFields, $spiFields)
3364
    {
3365
        $existingFields = [
3366
            new Field(
3367
                [
3368
                    'id' => '100',
3369
                    'fieldDefIdentifier' => 'identifier',
3370
                    'value' => 'initialValue',
3371
                    'languageCode' => 'eng-GB',
3372
                ]
3373
            ),
3374
        ];
3375
3376
        $fieldDefinitions = [
3377
            new FieldDefinition(
3378
                [
3379
                    'id' => 'fieldDefinitionId',
3380
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
3381
                    'isTranslatable' => false,
3382
                    'identifier' => 'identifier',
3383
                    'isRequired' => false,
3384
                    'defaultValue' => 'defaultValue',
3385
                ]
3386
            ),
3387
        ];
3388
3389
        $this->assertForTestUpdateContentNonRedundantFieldSet(
3390
            $initialLanguageCode,
3391
            $structFields,
3392
            $spiFields,
3393
            $existingFields,
3394
            $fieldDefinitions
3395
        );
3396
    }
3397
3398
    public function providerForTestUpdateContentNonRedundantFieldSet2()
3399
    {
3400
        $spiFields0 = [
3401
            new SPIField(
3402
                [
3403
                    'id' => '100',
3404
                    'fieldDefinitionId' => 'fieldDefinitionId',
3405
                    'type' => 'fieldTypeIdentifier',
3406
                    'value' => 'newValue',
3407
                    'languageCode' => 'eng-GB',
3408
                    'versionNo' => 7,
3409
                ]
3410
            ),
3411
        ];
3412
        $spiFields1 = [
3413
            new SPIField(
3414
                [
3415
                    'id' => null,
3416
                    'fieldDefinitionId' => 'fieldDefinitionId',
3417
                    'type' => 'fieldTypeIdentifier',
3418
                    'value' => 'newValue',
3419
                    'languageCode' => 'eng-US',
3420
                    'versionNo' => 7,
3421
                ]
3422
            ),
3423
        ];
3424
        $spiFields2 = [
3425
            new SPIField(
3426
                [
3427
                    'id' => 100,
3428
                    'fieldDefinitionId' => 'fieldDefinitionId',
3429
                    'type' => 'fieldTypeIdentifier',
3430
                    'value' => 'newValue2',
3431
                    'languageCode' => 'eng-GB',
3432
                    'versionNo' => 7,
3433
                ]
3434
            ),
3435
            new SPIField(
3436
                [
3437
                    'id' => null,
3438
                    'fieldDefinitionId' => 'fieldDefinitionId',
3439
                    'type' => 'fieldTypeIdentifier',
3440
                    'value' => 'newValue1',
3441
                    'languageCode' => 'eng-US',
3442
                    'versionNo' => 7,
3443
                ]
3444
            ),
3445
        ];
3446
3447
        return [
3448
            // 0. With languages set
3449
            [
3450
                'eng-GB',
3451
                [
3452
                    new Field(
3453
                        [
3454
                            'fieldDefIdentifier' => 'identifier',
3455
                            'value' => 'newValue',
3456
                            'languageCode' => 'eng-GB',
3457
                        ]
3458
                    ),
3459
                ],
3460
                $spiFields0,
3461
            ],
3462
            // 1. Without languages set
3463
            [
3464
                null,
3465
                [
3466
                    new Field(
3467
                        [
3468
                            'fieldDefIdentifier' => 'identifier',
3469
                            'value' => 'newValue',
3470
                            'languageCode' => null,
3471
                        ]
3472
                    ),
3473
                ],
3474
                $spiFields0,
3475
            ],
3476
            // 2. New language with language set
3477
            [
3478
                'eng-GB',
3479
                [
3480
                    new Field(
3481
                        [
3482
                            'fieldDefIdentifier' => 'identifier',
3483
                            'value' => 'newValue',
3484
                            'languageCode' => 'eng-US',
3485
                        ]
3486
                    ),
3487
                ],
3488
                $spiFields1,
3489
            ],
3490
            // 3. New language without language set
3491
            [
3492
                'eng-US',
3493
                [
3494
                    new Field(
3495
                        [
3496
                            'fieldDefIdentifier' => 'identifier',
3497
                            'value' => 'newValue',
3498
                            'languageCode' => null,
3499
                        ]
3500
                    ),
3501
                ],
3502
                $spiFields1,
3503
            ],
3504
            // 4. New language and existing language with language set
3505
            [
3506
                'eng-GB',
3507
                [
3508
                    new Field(
3509
                        [
3510
                            'fieldDefIdentifier' => 'identifier',
3511
                            'value' => 'newValue1',
3512
                            'languageCode' => 'eng-US',
3513
                        ]
3514
                    ),
3515
                    new Field(
3516
                        [
3517
                            'fieldDefIdentifier' => 'identifier',
3518
                            'value' => 'newValue2',
3519
                            'languageCode' => 'eng-GB',
3520
                        ]
3521
                    ),
3522
                ],
3523
                $spiFields2,
3524
            ],
3525
            // 5. New language and existing language without language set
3526
            [
3527
                'eng-US',
3528
                [
3529
                    new Field(
3530
                        [
3531
                            'fieldDefIdentifier' => 'identifier',
3532
                            'value' => 'newValue1',
3533
                            'languageCode' => null,
3534
                        ]
3535
                    ),
3536
                    new Field(
3537
                        [
3538
                            'fieldDefIdentifier' => 'identifier',
3539
                            'value' => 'newValue2',
3540
                            'languageCode' => 'eng-GB',
3541
                        ]
3542
                    ),
3543
                ],
3544
                $spiFields2,
3545
            ],
3546
            // 6. Adding new language without fields
3547
            [
3548
                'eng-US',
3549
                [],
3550
                [
3551
                    new SPIField(
3552
                        [
3553
                            'id' => null,
3554
                            'fieldDefinitionId' => 'fieldDefinitionId',
3555
                            'type' => 'fieldTypeIdentifier',
3556
                            'value' => 'defaultValue',
3557
                            'languageCode' => 'eng-US',
3558
                            'versionNo' => 7,
3559
                        ]
3560
                    ),
3561
                ],
3562
            ],
3563
        ];
3564
    }
3565
3566
    /**
3567
     * Test for the updateContent() method.
3568
     *
3569
     * Testing with translatable field.
3570
     *
3571
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForUpdate
3572
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForUpdate
3573
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContent
3574
     * @dataProvider providerForTestUpdateContentNonRedundantFieldSet2
3575
     */
3576 View Code Duplication
    public function testUpdateContentNonRedundantFieldSet2($initialLanguageCode, $structFields, $spiFields)
3577
    {
3578
        $existingFields = [
3579
            new Field(
3580
                [
3581
                    'id' => '100',
3582
                    'fieldDefIdentifier' => 'identifier',
3583
                    'value' => 'initialValue',
3584
                    'languageCode' => 'eng-GB',
3585
                ]
3586
            ),
3587
        ];
3588
3589
        $fieldDefinitions = [
3590
            new FieldDefinition(
3591
                [
3592
                    'id' => 'fieldDefinitionId',
3593
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
3594
                    'isTranslatable' => true,
3595
                    'identifier' => 'identifier',
3596
                    'isRequired' => false,
3597
                    'defaultValue' => 'defaultValue',
3598
                ]
3599
            ),
3600
        ];
3601
3602
        $this->assertForTestUpdateContentNonRedundantFieldSet(
3603
            $initialLanguageCode,
3604
            $structFields,
3605
            $spiFields,
3606
            $existingFields,
3607
            $fieldDefinitions
3608
        );
3609
    }
3610
3611
    public function providerForTestUpdateContentNonRedundantFieldSet3()
3612
    {
3613
        $spiFields0 = [
3614
            new SPIField(
3615
                [
3616
                    'id' => null,
3617
                    'fieldDefinitionId' => 'fieldDefinitionId1',
3618
                    'type' => 'fieldTypeIdentifier',
3619
                    'value' => 'newValue1',
3620
                    'languageCode' => 'eng-US',
3621
                    'versionNo' => 7,
3622
                ]
3623
            ),
3624
        ];
3625
        $spiFields1 = [
3626
            new SPIField(
3627
                [
3628
                    'id' => 100,
3629
                    'fieldDefinitionId' => 'fieldDefinitionId1',
3630
                    'type' => 'fieldTypeIdentifier',
3631
                    'value' => 'newValue2',
3632
                    'languageCode' => 'eng-GB',
3633
                    'versionNo' => 7,
3634
                ]
3635
            ),
3636
            new SPIField(
3637
                [
3638
                    'id' => null,
3639
                    'fieldDefinitionId' => 'fieldDefinitionId1',
3640
                    'type' => 'fieldTypeIdentifier',
3641
                    'value' => 'newValue1',
3642
                    'languageCode' => 'eng-US',
3643
                    'versionNo' => 7,
3644
                ]
3645
            ),
3646
        ];
3647
        $spiFields2 = [
3648
            new SPIField(
3649
                [
3650
                    'id' => 100,
3651
                    'fieldDefinitionId' => 'fieldDefinitionId1',
3652
                    'type' => 'fieldTypeIdentifier',
3653
                    'value' => 'newValue2',
3654
                    'languageCode' => 'eng-GB',
3655
                    'versionNo' => 7,
3656
                ]
3657
            ),
3658
            new SPIField(
3659
                [
3660
                    'id' => null,
3661
                    'fieldDefinitionId' => 'fieldDefinitionId1',
3662
                    'type' => 'fieldTypeIdentifier',
3663
                    'value' => 'newValue1',
3664
                    'languageCode' => 'eng-US',
3665
                    'versionNo' => 7,
3666
                ]
3667
            ),
3668
            new SPIField(
3669
                [
3670
                    'id' => 101,
3671
                    'fieldDefinitionId' => 'fieldDefinitionId2',
3672
                    'type' => 'fieldTypeIdentifier',
3673
                    'value' => 'newValue3',
3674
                    'languageCode' => 'eng-GB',
3675
                    'versionNo' => 7,
3676
                ]
3677
            ),
3678
        ];
3679
        $spiFields3 = [
3680
            new SPIField(
3681
                [
3682
                    'id' => null,
3683
                    'fieldDefinitionId' => 'fieldDefinitionId1',
3684
                    'type' => 'fieldTypeIdentifier',
3685
                    'value' => 'defaultValue1',
3686
                    'languageCode' => 'eng-US',
3687
                    'versionNo' => 7,
3688
                ]
3689
            ),
3690
        ];
3691
3692
        return [
3693
            // 0. ew language with language set
3694
            [
3695
                'eng-US',
3696
                [
3697
                    new Field(
3698
                        [
3699
                            'fieldDefIdentifier' => 'identifier1',
3700
                            'value' => 'newValue1',
3701
                            'languageCode' => 'eng-US',
3702
                        ]
3703
                    ),
3704
                ],
3705
                $spiFields0,
3706
            ],
3707
            // 1. New language without language set
3708
            [
3709
                'eng-US',
3710
                [
3711
                    new Field(
3712
                        [
3713
                            'fieldDefIdentifier' => 'identifier1',
3714
                            'value' => 'newValue1',
3715
                            'languageCode' => null,
3716
                        ]
3717
                    ),
3718
                ],
3719
                $spiFields0,
3720
            ],
3721
            // 2. New language and existing language with language set
3722
            [
3723
                'eng-US',
3724
                [
3725
                    new Field(
3726
                        [
3727
                            'fieldDefIdentifier' => 'identifier1',
3728
                            'value' => 'newValue1',
3729
                            'languageCode' => 'eng-US',
3730
                        ]
3731
                    ),
3732
                    new Field(
3733
                        [
3734
                            'fieldDefIdentifier' => 'identifier1',
3735
                            'value' => 'newValue2',
3736
                            'languageCode' => 'eng-GB',
3737
                        ]
3738
                    ),
3739
                ],
3740
                $spiFields1,
3741
            ],
3742
            // 3. New language and existing language without language set
3743
            [
3744
                'eng-US',
3745
                [
3746
                    new Field(
3747
                        [
3748
                            'fieldDefIdentifier' => 'identifier1',
3749
                            'value' => 'newValue1',
3750
                            'languageCode' => null,
3751
                        ]
3752
                    ),
3753
                    new Field(
3754
                        [
3755
                            'fieldDefIdentifier' => 'identifier1',
3756
                            'value' => 'newValue2',
3757
                            'languageCode' => 'eng-GB',
3758
                        ]
3759
                    ),
3760
                ],
3761
                $spiFields1,
3762
            ],
3763
            // 4. New language and existing language with untranslatable field, with language set
3764
            [
3765
                'eng-US',
3766
                [
3767
                    new Field(
3768
                        [
3769
                            'fieldDefIdentifier' => 'identifier1',
3770
                            'value' => 'newValue1',
3771
                            'languageCode' => 'eng-US',
3772
                        ]
3773
                    ),
3774
                    new Field(
3775
                        [
3776
                            'fieldDefIdentifier' => 'identifier1',
3777
                            'value' => 'newValue2',
3778
                            'languageCode' => 'eng-GB',
3779
                        ]
3780
                    ),
3781
                    new Field(
3782
                        [
3783
                            'fieldDefIdentifier' => 'identifier2',
3784
                            'value' => 'newValue3',
3785
                            'languageCode' => 'eng-GB',
3786
                        ]
3787
                    ),
3788
                ],
3789
                $spiFields2,
3790
            ],
3791
            // 5. New language and existing language with untranslatable field, without language set
3792
            [
3793
                'eng-US',
3794
                [
3795
                    new Field(
3796
                        [
3797
                            'fieldDefIdentifier' => 'identifier1',
3798
                            'value' => 'newValue1',
3799
                            'languageCode' => null,
3800
                        ]
3801
                    ),
3802
                    new Field(
3803
                        [
3804
                            'fieldDefIdentifier' => 'identifier1',
3805
                            'value' => 'newValue2',
3806
                            'languageCode' => 'eng-GB',
3807
                        ]
3808
                    ),
3809
                    new Field(
3810
                        [
3811
                            'fieldDefIdentifier' => 'identifier2',
3812
                            'value' => 'newValue3',
3813
                            'languageCode' => null,
3814
                        ]
3815
                    ),
3816
                ],
3817
                $spiFields2,
3818
            ],
3819
            // 6. Adding new language without fields
3820
            [
3821
                'eng-US',
3822
                [],
3823
                $spiFields3,
3824
            ],
3825
        ];
3826
    }
3827
3828
    /**
3829
     * Test for the updateContent() method.
3830
     *
3831
     * Testing with new language and untranslatable field.
3832
     *
3833
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForUpdate
3834
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForUpdate
3835
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContent
3836
     * @dataProvider providerForTestUpdateContentNonRedundantFieldSet3
3837
     */
3838
    public function testUpdateContentNonRedundantFieldSet3($initialLanguageCode, $structFields, $spiFields)
3839
    {
3840
        $existingFields = [
3841
            new Field(
3842
                [
3843
                    'id' => '100',
3844
                    'fieldDefIdentifier' => 'identifier1',
3845
                    'value' => 'initialValue1',
3846
                    'languageCode' => 'eng-GB',
3847
                ]
3848
            ),
3849
            new Field(
3850
                [
3851
                    'id' => '101',
3852
                    'fieldDefIdentifier' => 'identifier2',
3853
                    'value' => 'initialValue2',
3854
                    'languageCode' => 'eng-GB',
3855
                ]
3856
            ),
3857
        ];
3858
3859
        $fieldDefinitions = [
3860
            new FieldDefinition(
3861
                [
3862
                    'id' => 'fieldDefinitionId1',
3863
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
3864
                    'isTranslatable' => true,
3865
                    'identifier' => 'identifier1',
3866
                    'isRequired' => false,
3867
                    'defaultValue' => 'defaultValue1',
3868
                ]
3869
            ),
3870
            new FieldDefinition(
3871
                [
3872
                    'id' => 'fieldDefinitionId2',
3873
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
3874
                    'isTranslatable' => false,
3875
                    'identifier' => 'identifier2',
3876
                    'isRequired' => false,
3877
                    'defaultValue' => 'defaultValue2',
3878
                ]
3879
            ),
3880
        ];
3881
3882
        $this->assertForTestUpdateContentNonRedundantFieldSet(
3883
            $initialLanguageCode,
3884
            $structFields,
3885
            $spiFields,
3886
            $existingFields,
3887
            $fieldDefinitions
3888
        );
3889
    }
3890
3891
    public function providerForTestUpdateContentNonRedundantFieldSet4()
3892
    {
3893
        $spiFields0 = [
3894
            new SPIField(
3895
                [
3896
                    'id' => null,
3897
                    'fieldDefinitionId' => 'fieldDefinitionId1',
3898
                    'type' => 'fieldTypeIdentifier',
3899
                    'value' => 'newValue1',
3900
                    'languageCode' => 'eng-US',
3901
                    'versionNo' => 7,
3902
                ]
3903
            ),
3904
        ];
3905
        $spiFields1 = [
3906
            new SPIField(
3907
                [
3908
                    'id' => 100,
3909
                    'fieldDefinitionId' => 'fieldDefinitionId1',
3910
                    'type' => 'fieldTypeIdentifier',
3911
                    'value' => self::EMPTY_FIELD_VALUE,
3912
                    'languageCode' => 'eng-GB',
3913
                    'versionNo' => 7,
3914
                ]
3915
            ),
3916
            new SPIField(
3917
                [
3918
                    'id' => null,
3919
                    'fieldDefinitionId' => 'fieldDefinitionId1',
3920
                    'type' => 'fieldTypeIdentifier',
3921
                    'value' => 'newValue1',
3922
                    'languageCode' => 'eng-US',
3923
                    'versionNo' => 7,
3924
                ]
3925
            ),
3926
        ];
3927
        $spiFields2 = [
3928
            new SPIField(
3929
                [
3930
                    'id' => 100,
3931
                    'fieldDefinitionId' => 'fieldDefinitionId1',
3932
                    'type' => 'fieldTypeIdentifier',
3933
                    'value' => self::EMPTY_FIELD_VALUE,
3934
                    'languageCode' => 'eng-GB',
3935
                    'versionNo' => 7,
3936
                ]
3937
            ),
3938
        ];
3939
3940
        return [
3941
            // 0. New translation with empty field by default
3942
            [
3943
                'eng-US',
3944
                [
3945
                    new Field(
3946
                        [
3947
                            'fieldDefIdentifier' => 'identifier1',
3948
                            'value' => 'newValue1',
3949
                            'languageCode' => 'eng-US',
3950
                        ]
3951
                    ),
3952
                ],
3953
                $spiFields0,
3954
            ],
3955
            // 1. New translation with empty field by default, without language set
3956
            [
3957
                'eng-US',
3958
                [
3959
                    new Field(
3960
                        [
3961
                            'fieldDefIdentifier' => 'identifier1',
3962
                            'value' => 'newValue1',
3963
                            'languageCode' => null,
3964
                        ]
3965
                    ),
3966
                ],
3967
                $spiFields0,
3968
            ],
3969
            // 2. New translation with empty field given
3970
            [
3971
                'eng-US',
3972
                [
3973
                    new Field(
3974
                        [
3975
                            'fieldDefIdentifier' => 'identifier1',
3976
                            'value' => 'newValue1',
3977
                            'languageCode' => 'eng-US',
3978
                        ]
3979
                    ),
3980
                    new Field(
3981
                        [
3982
                            'fieldDefIdentifier' => 'identifier2',
3983
                            'value' => self::EMPTY_FIELD_VALUE,
3984
                            'languageCode' => 'eng-US',
3985
                        ]
3986
                    ),
3987
                ],
3988
                $spiFields0,
3989
            ],
3990
            // 3. New translation with empty field given, without language set
3991
            [
3992
                'eng-US',
3993
                [
3994
                    new Field(
3995
                        [
3996
                            'fieldDefIdentifier' => 'identifier1',
3997
                            'value' => 'newValue1',
3998
                            'languageCode' => null,
3999
                        ]
4000
                    ),
4001
                    new Field(
4002
                        [
4003
                            'fieldDefIdentifier' => 'identifier2',
4004
                            'value' => self::EMPTY_FIELD_VALUE,
4005
                            'languageCode' => null,
4006
                        ]
4007
                    ),
4008
                ],
4009
                $spiFields0,
4010
            ],
4011
            // 4. Updating existing language with empty value
4012
            [
4013
                'eng-US',
4014
                [
4015
                    new Field(
4016
                        [
4017
                            'fieldDefIdentifier' => 'identifier1',
4018
                            'value' => 'newValue1',
4019
                            'languageCode' => 'eng-US',
4020
                        ]
4021
                    ),
4022
                    new Field(
4023
                        [
4024
                            'fieldDefIdentifier' => 'identifier1',
4025
                            'value' => self::EMPTY_FIELD_VALUE,
4026
                            'languageCode' => 'eng-GB',
4027
                        ]
4028
                    ),
4029
                ],
4030
                $spiFields1,
4031
            ],
4032
            // 5. Updating existing language with empty value, without language set
4033
            [
4034
                'eng-US',
4035
                [
4036
                    new Field(
4037
                        [
4038
                            'fieldDefIdentifier' => 'identifier1',
4039
                            'value' => 'newValue1',
4040
                            'languageCode' => null,
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
            // 6. Updating existing language with empty value and adding new language with empty value
4054
            [
4055
                'eng-US',
4056
                [
4057
                    new Field(
4058
                        [
4059
                            'fieldDefIdentifier' => 'identifier1',
4060
                            'value' => self::EMPTY_FIELD_VALUE,
4061
                            'languageCode' => 'eng-US',
4062
                        ]
4063
                    ),
4064
                    new Field(
4065
                        [
4066
                            'fieldDefIdentifier' => 'identifier1',
4067
                            'value' => self::EMPTY_FIELD_VALUE,
4068
                            'languageCode' => 'eng-GB',
4069
                        ]
4070
                    ),
4071
                ],
4072
                $spiFields2,
4073
            ],
4074
            // 7. Updating existing language with empty value and adding new language with empty value,
4075
            // without language set
4076
            [
4077
                'eng-US',
4078
                [
4079
                    new Field(
4080
                        [
4081
                            'fieldDefIdentifier' => 'identifier1',
4082
                            'value' => self::EMPTY_FIELD_VALUE,
4083
                            'languageCode' => null,
4084
                        ]
4085
                    ),
4086
                    new Field(
4087
                        [
4088
                            'fieldDefIdentifier' => 'identifier1',
4089
                            'value' => self::EMPTY_FIELD_VALUE,
4090
                            'languageCode' => 'eng-GB',
4091
                        ]
4092
                    ),
4093
                ],
4094
                $spiFields2,
4095
            ],
4096
            // 8. Adding new language with no fields given
4097
            [
4098
                'eng-US',
4099
                [],
4100
                [],
4101
            ],
4102
            // 9. Adding new language with fields
4103
            [
4104
                'eng-US',
4105
                [
4106
                    new Field(
4107
                        [
4108
                            'fieldDefIdentifier' => 'identifier1',
4109
                            'value' => self::EMPTY_FIELD_VALUE,
4110
                            'languageCode' => 'eng-US',
4111
                        ]
4112
                    ),
4113
                ],
4114
                [],
4115
            ],
4116
            // 10. Adding new language with fields, without language set
4117
            [
4118
                'eng-US',
4119
                [
4120
                    new Field(
4121
                        [
4122
                            'fieldDefIdentifier' => 'identifier1',
4123
                            'value' => self::EMPTY_FIELD_VALUE,
4124
                            'languageCode' => null,
4125
                        ]
4126
                    ),
4127
                ],
4128
                [],
4129
            ],
4130
        ];
4131
    }
4132
4133
    /**
4134
     * Test for the updateContent() method.
4135
     *
4136
     * Testing with empty values.
4137
     *
4138
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForUpdate
4139
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForUpdate
4140
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContent
4141
     * @dataProvider providerForTestUpdateContentNonRedundantFieldSet4
4142
     */
4143
    public function testUpdateContentNonRedundantFieldSet4($initialLanguageCode, $structFields, $spiFields)
4144
    {
4145
        $existingFields = [
4146
            new Field(
4147
                [
4148
                    'id' => '100',
4149
                    'fieldDefIdentifier' => 'identifier1',
4150
                    'value' => 'initialValue1',
4151
                    'languageCode' => 'eng-GB',
4152
                ]
4153
            ),
4154
            new Field(
4155
                [
4156
                    'id' => '101',
4157
                    'fieldDefIdentifier' => 'identifier2',
4158
                    'value' => 'initialValue2',
4159
                    'languageCode' => 'eng-GB',
4160
                ]
4161
            ),
4162
        ];
4163
4164
        $fieldDefinitions = [
4165
            new FieldDefinition(
4166
                [
4167
                    'id' => 'fieldDefinitionId1',
4168
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
4169
                    'isTranslatable' => true,
4170
                    'identifier' => 'identifier1',
4171
                    'isRequired' => false,
4172
                    'defaultValue' => self::EMPTY_FIELD_VALUE,
4173
                ]
4174
            ),
4175
            new FieldDefinition(
4176
                [
4177
                    'id' => 'fieldDefinitionId2',
4178
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
4179
                    'isTranslatable' => true,
4180
                    'identifier' => 'identifier2',
4181
                    'isRequired' => false,
4182
                    'defaultValue' => self::EMPTY_FIELD_VALUE,
4183
                ]
4184
            ),
4185
        ];
4186
4187
        $this->assertForTestUpdateContentNonRedundantFieldSet(
4188
            $initialLanguageCode,
4189
            $structFields,
4190
            $spiFields,
4191
            $existingFields,
4192
            $fieldDefinitions
4193
        );
4194
    }
4195
4196
    /**
4197
     * @todo add first field empty
4198
     *
4199
     * @return array
4200
     */
4201
    public function providerForTestUpdateContentNonRedundantFieldSetComplex()
4202
    {
4203
        $spiFields0 = [
4204
            new SPIField(
4205
                [
4206
                    'id' => 100,
4207
                    'fieldDefinitionId' => 'fieldDefinitionId1',
4208
                    'type' => 'fieldTypeIdentifier',
4209
                    'value' => 'newValue1-eng-GB',
4210
                    'languageCode' => 'eng-GB',
4211
                    'versionNo' => 7,
4212
                ]
4213
            ),
4214
            new SPIField(
4215
                [
4216
                    'id' => null,
4217
                    'fieldDefinitionId' => 'fieldDefinitionId4',
4218
                    'type' => 'fieldTypeIdentifier',
4219
                    'value' => 'newValue4',
4220
                    'languageCode' => 'eng-US',
4221
                    'versionNo' => 7,
4222
                ]
4223
            ),
4224
        ];
4225
        $spiFields1 = [
4226
            new SPIField(
4227
                [
4228
                    'id' => 100,
4229
                    'fieldDefinitionId' => 'fieldDefinitionId1',
4230
                    'type' => 'fieldTypeIdentifier',
4231
                    'value' => 'newValue1-eng-GB',
4232
                    'languageCode' => 'eng-GB',
4233
                    'versionNo' => 7,
4234
                ]
4235
            ),
4236
            new SPIField(
4237
                [
4238
                    'id' => null,
4239
                    'fieldDefinitionId' => 'fieldDefinitionId2',
4240
                    'type' => 'fieldTypeIdentifier',
4241
                    'value' => 'newValue2',
4242
                    'languageCode' => 'eng-US',
4243
                    'versionNo' => 7,
4244
                ]
4245
            ),
4246
            new SPIField(
4247
                [
4248
                    'id' => null,
4249
                    'fieldDefinitionId' => 'fieldDefinitionId4',
4250
                    'type' => 'fieldTypeIdentifier',
4251
                    'value' => 'defaultValue4',
4252
                    'languageCode' => 'eng-US',
4253
                    'versionNo' => 7,
4254
                ]
4255
            ),
4256
        ];
4257
        $spiFields2 = [
4258
            new SPIField(
4259
                [
4260
                    'id' => 100,
4261
                    'fieldDefinitionId' => 'fieldDefinitionId1',
4262
                    'type' => 'fieldTypeIdentifier',
4263
                    'value' => 'newValue1-eng-GB',
4264
                    'languageCode' => 'eng-GB',
4265
                    'versionNo' => 7,
4266
                ]
4267
            ),
4268
            new SPIField(
4269
                [
4270
                    'id' => null,
4271
                    'fieldDefinitionId' => 'fieldDefinitionId2',
4272
                    'type' => 'fieldTypeIdentifier',
4273
                    'value' => 'newValue2',
4274
                    'languageCode' => 'eng-US',
4275
                    'versionNo' => 7,
4276
                ]
4277
            ),
4278
            new SPIField(
4279
                [
4280
                    'id' => null,
4281
                    'fieldDefinitionId' => 'fieldDefinitionId4',
4282
                    'type' => 'fieldTypeIdentifier',
4283
                    'value' => 'defaultValue4',
4284
                    'languageCode' => 'ger-DE',
4285
                    'versionNo' => 7,
4286
                ]
4287
            ),
4288
            new SPIField(
4289
                [
4290
                    'id' => null,
4291
                    'fieldDefinitionId' => 'fieldDefinitionId4',
4292
                    'type' => 'fieldTypeIdentifier',
4293
                    'value' => 'defaultValue4',
4294
                    'languageCode' => 'eng-US',
4295
                    'versionNo' => 7,
4296
                ]
4297
            ),
4298
        ];
4299
4300
        return [
4301
            // 0. Add new language and update existing
4302
            [
4303
                'eng-US',
4304
                [
4305
                    new Field(
4306
                        [
4307
                            'fieldDefIdentifier' => 'identifier4',
4308
                            'value' => 'newValue4',
4309
                            'languageCode' => 'eng-US',
4310
                        ]
4311
                    ),
4312
                    new Field(
4313
                        [
4314
                            'fieldDefIdentifier' => 'identifier1',
4315
                            'value' => 'newValue1-eng-GB',
4316
                            'languageCode' => 'eng-GB',
4317
                        ]
4318
                    ),
4319
                ],
4320
                $spiFields0,
4321
            ],
4322
            // 1. Add new language and update existing, without language set
4323
            [
4324
                'eng-US',
4325
                [
4326
                    new Field(
4327
                        [
4328
                            'fieldDefIdentifier' => 'identifier4',
4329
                            'value' => 'newValue4',
4330
                            'languageCode' => null,
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
            // 2. Add new language and update existing variant
4344
            [
4345
                'eng-US',
4346
                [
4347
                    new Field(
4348
                        [
4349
                            'fieldDefIdentifier' => 'identifier2',
4350
                            'value' => 'newValue2',
4351
                            'languageCode' => 'eng-US',
4352
                        ]
4353
                    ),
4354
                    new Field(
4355
                        [
4356
                            'fieldDefIdentifier' => 'identifier1',
4357
                            'value' => 'newValue1-eng-GB',
4358
                            'languageCode' => 'eng-GB',
4359
                        ]
4360
                    ),
4361
                ],
4362
                $spiFields1,
4363
            ],
4364
            // 3. Add new language and update existing variant, without language set
4365
            [
4366
                'eng-US',
4367
                [
4368
                    new Field(
4369
                        [
4370
                            'fieldDefIdentifier' => 'identifier2',
4371
                            'value' => 'newValue2',
4372
                            'languageCode' => null,
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
            // 4. Update with multiple languages
4386
            [
4387
                'ger-DE',
4388
                [
4389
                    new Field(
4390
                        [
4391
                            'fieldDefIdentifier' => 'identifier2',
4392
                            'value' => 'newValue2',
4393
                            'languageCode' => 'eng-US',
4394
                        ]
4395
                    ),
4396
                    new Field(
4397
                        [
4398
                            'fieldDefIdentifier' => 'identifier1',
4399
                            'value' => 'newValue1-eng-GB',
4400
                            'languageCode' => 'eng-GB',
4401
                        ]
4402
                    ),
4403
                ],
4404
                $spiFields2,
4405
            ],
4406
            // 5. Update with multiple languages without language set
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' => null,
4422
                        ]
4423
                    ),
4424
                ],
4425
                $spiFields2,
4426
            ],
4427
        ];
4428
    }
4429
4430
    protected function fixturesForTestUpdateContentNonRedundantFieldSetComplex()
4431
    {
4432
        $existingFields = [
4433
            new Field(
4434
                [
4435
                    'id' => '100',
4436
                    'fieldDefIdentifier' => 'identifier1',
4437
                    'value' => 'initialValue1',
4438
                    'languageCode' => 'eng-GB',
4439
                ]
4440
            ),
4441
            new Field(
4442
                [
4443
                    'id' => '101',
4444
                    'fieldDefIdentifier' => 'identifier2',
4445
                    'value' => 'initialValue2',
4446
                    'languageCode' => 'eng-GB',
4447
                ]
4448
            ),
4449
            new Field(
4450
                [
4451
                    'id' => '102',
4452
                    'fieldDefIdentifier' => 'identifier3',
4453
                    'value' => 'initialValue3',
4454
                    'languageCode' => 'eng-GB',
4455
                ]
4456
            ),
4457
            new Field(
4458
                [
4459
                    'id' => '103',
4460
                    'fieldDefIdentifier' => 'identifier4',
4461
                    'value' => 'initialValue4',
4462
                    'languageCode' => 'eng-GB',
4463
                ]
4464
            ),
4465
        ];
4466
4467
        $fieldDefinitions = [
4468
            new FieldDefinition(
4469
                [
4470
                    'id' => 'fieldDefinitionId1',
4471
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
4472
                    'isTranslatable' => false,
4473
                    'identifier' => 'identifier1',
4474
                    'isRequired' => false,
4475
                    'defaultValue' => self::EMPTY_FIELD_VALUE,
4476
                ]
4477
            ),
4478
            new FieldDefinition(
4479
                [
4480
                    'id' => 'fieldDefinitionId2',
4481
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
4482
                    'isTranslatable' => true,
4483
                    'identifier' => 'identifier2',
4484
                    'isRequired' => false,
4485
                    'defaultValue' => self::EMPTY_FIELD_VALUE,
4486
                ]
4487
            ),
4488
            new FieldDefinition(
4489
                [
4490
                    'id' => 'fieldDefinitionId3',
4491
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
4492
                    'isTranslatable' => false,
4493
                    'identifier' => 'identifier3',
4494
                    'isRequired' => false,
4495
                    'defaultValue' => 'defaultValue3',
4496
                ]
4497
            ),
4498
            new FieldDefinition(
4499
                [
4500
                    'id' => 'fieldDefinitionId4',
4501
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
4502
                    'isTranslatable' => true,
4503
                    'identifier' => 'identifier4',
4504
                    'isRequired' => false,
4505
                    'defaultValue' => 'defaultValue4',
4506
                ]
4507
            ),
4508
        ];
4509
4510
        return [$existingFields, $fieldDefinitions];
4511
    }
4512
4513
    /**
4514
     * Test for the updateContent() method.
4515
     *
4516
     * Testing more complex cases.
4517
     *
4518
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForUpdate
4519
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForUpdate
4520
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContent
4521
     * @dataProvider providerForTestUpdateContentNonRedundantFieldSetComplex
4522
     */
4523
    public function testUpdateContentNonRedundantFieldSetComplex($initialLanguageCode, $structFields, $spiFields)
4524
    {
4525
        list($existingFields, $fieldDefinitions) = $this->fixturesForTestUpdateContentNonRedundantFieldSetComplex();
4526
4527
        $this->assertForTestUpdateContentNonRedundantFieldSet(
4528
            $initialLanguageCode,
4529
            $structFields,
4530
            $spiFields,
4531
            $existingFields,
4532
            $fieldDefinitions
4533
        );
4534
    }
4535
4536 View Code Duplication
    public function providerForTestUpdateContentWithInvalidLanguage()
4537
    {
4538
        return [
4539
            [
4540
                'eng-GB',
4541
                [
4542
                    new Field(
4543
                        [
4544
                            'fieldDefIdentifier' => 'identifier',
4545
                            'value' => 'newValue',
4546
                            'languageCode' => 'Klingon',
4547
                        ]
4548
                    ),
4549
                ],
4550
            ],
4551
            [
4552
                'Klingon',
4553
                [
4554
                    new Field(
4555
                        [
4556
                            'fieldDefIdentifier' => 'identifier',
4557
                            'value' => 'newValue',
4558
                            'languageCode' => 'eng-GB',
4559
                        ]
4560
                    ),
4561
                ],
4562
            ],
4563
        ];
4564
    }
4565
4566
    /**
4567
     * Test for the updateContent() method.
4568
     *
4569
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForUpdate
4570
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContent
4571
     * @dataProvider providerForTestUpdateContentWithInvalidLanguage
4572
     */
4573
    public function testUpdateContentWithInvalidLanguage($initialLanguageCode, $structFields)
4574
    {
4575
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\NotFoundException::class);
4576
        $this->expectExceptionMessage('Could not find \'Language\' with identifier \'Klingon\'');
4577
4578
        $repositoryMock = $this->getRepositoryMock();
0 ignored issues
show
Unused Code introduced by
$repositoryMock is not used, you could remove the assignment.

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

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

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

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

Loading history...
4579
        $permissionResolverMock = $this->getPermissionResolverMock();
4580
        $mockedService = $this->getPartlyMockedContentService(['loadContent']);
4581
        /** @var \PHPUnit\Framework\MockObject\MockObject $languageHandlerMock */
4582
        $languageHandlerMock = $this->getPersistenceMock()->contentLanguageHandler();
4583
        $versionInfo = new VersionInfo(
4584
            [
4585
                'contentInfo' => new ContentInfo(
4586
                    [
4587
                        'id' => 42,
4588
                        'contentTypeId' => 24,
4589
                        'mainLanguageCode' => 'eng-GB',
4590
                    ]
4591
                ),
4592
                'versionNo' => 7,
4593
                'languageCodes' => ['eng-GB'],
4594
                'status' => VersionInfo::STATUS_DRAFT,
4595
            ]
4596
        );
4597
        $content = new Content(
4598
            [
4599
                'versionInfo' => $versionInfo,
4600
                'internalFields' => [],
4601
            ]
4602
        );
4603
4604
        $languageHandlerMock->expects($this->any())
4605
            ->method('loadByLanguageCode')
4606
            ->with($this->isType('string'))
4607
            ->will(
4608
                $this->returnCallback(
4609 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...
4610
                        if ($languageCode === 'Klingon') {
4611
                            throw new NotFoundException('Language', 'Klingon');
4612
                        }
4613
4614
                        return new Language(['id' => 4242]);
4615
                    }
4616
                )
4617
            );
4618
4619
        $mockedService->expects($this->once())
4620
            ->method('loadContent')
4621
            ->with(
4622
                $this->equalTo(42),
4623
                $this->equalTo(null),
4624
                $this->equalTo(7)
4625
            )->will(
4626
                $this->returnValue($content)
4627
            );
4628
4629
        $permissionResolverMock->expects($this->once())
4630
            ->method('canUser')
4631
            ->with(
4632
                $this->equalTo('content'),
4633
                $this->equalTo('edit'),
4634
                $this->equalTo($content),
4635
                $this->isType('array')
4636
            )->will($this->returnValue(true));
4637
4638
        $contentUpdateStruct = new ContentUpdateStruct(
4639
            [
4640
                'fields' => $structFields,
4641
                'initialLanguageCode' => $initialLanguageCode,
4642
            ]
4643
        );
4644
4645
        $mockedService->updateContent($content->versionInfo, $contentUpdateStruct);
4646
    }
4647
4648
    protected function assertForUpdateContentContentValidationException(
4649
        $initialLanguageCode,
4650
        $structFields,
4651
        $fieldDefinitions = []
4652
    ) {
4653
        $repositoryMock = $this->getRepositoryMock();
4654
        $permissionResolverMock = $this->getPermissionResolverMock();
4655
        $mockedService = $this->getPartlyMockedContentService(['loadContent']);
4656
        /** @var \PHPUnit\Framework\MockObject\MockObject $languageHandlerMock */
4657
        $languageHandlerMock = $this->getPersistenceMock()->contentLanguageHandler();
4658
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
4659
        $versionInfo = new VersionInfo(
4660
            [
4661
                'contentInfo' => new ContentInfo(
4662
                    [
4663
                        'id' => 42,
4664
                        'contentTypeId' => 24,
4665
                        'mainLanguageCode' => 'eng-GB',
4666
                    ]
4667
                ),
4668
                'versionNo' => 7,
4669
                'languageCodes' => ['eng-GB'],
4670
                'status' => VersionInfo::STATUS_DRAFT,
4671
            ]
4672
        );
4673
        $content = new Content(
4674
            [
4675
                'versionInfo' => $versionInfo,
4676
                'internalFields' => [],
4677
            ]
4678
        );
4679
        $contentType = new ContentType(['fieldDefinitions' => $fieldDefinitions]);
4680
4681
        $languageHandlerMock->expects($this->any())
4682
            ->method('loadByLanguageCode')
4683
            ->with($this->isType('string'))
4684
            ->will(
4685
                $this->returnCallback(
4686 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...
4687
                        if ($languageCode === 'Klingon') {
4688
                            throw new NotFoundException('Language', 'Klingon');
4689
                        }
4690
4691
                        return new Language(['id' => 4242]);
4692
                    }
4693
                )
4694
            );
4695
4696
        $mockedService->expects($this->once())
4697
            ->method('loadContent')
4698
            ->with(
4699
                $this->equalTo(42),
4700
                $this->equalTo(null),
4701
                $this->equalTo(7)
4702
            )->will(
4703
                $this->returnValue($content)
4704
            );
4705
4706
        $permissionResolverMock->expects($this->once())
4707
            ->method('canUser')
4708
            ->with(
4709
                $this->equalTo('content'),
4710
                $this->equalTo('edit'),
4711
                $this->equalTo($content),
4712
                $this->isType('array')
4713
            )->will($this->returnValue(true));
4714
4715
        $contentTypeServiceMock->expects($this->once())
4716
            ->method('loadContentType')
4717
            ->with($this->equalTo(24))
4718
            ->will($this->returnValue($contentType));
4719
4720
        $repositoryMock->expects($this->once())
4721
            ->method('getContentTypeService')
4722
            ->will($this->returnValue($contentTypeServiceMock));
4723
4724
        $contentUpdateStruct = new ContentUpdateStruct(
4725
            [
4726
                'fields' => $structFields,
4727
                'initialLanguageCode' => $initialLanguageCode,
4728
            ]
4729
        );
4730
4731
        $mockedService->updateContent($content->versionInfo, $contentUpdateStruct);
4732
    }
4733
4734 View Code Duplication
    public function providerForTestUpdateContentThrowsContentValidationExceptionFieldDefinition()
4735
    {
4736
        return [
4737
            [
4738
                'eng-GB',
4739
                [
4740
                    new Field(
4741
                        [
4742
                            'fieldDefIdentifier' => 'identifier',
4743
                            'value' => 'newValue',
4744
                            'languageCode' => 'eng-GB',
4745
                        ]
4746
                    ),
4747
                ],
4748
            ],
4749
        ];
4750
    }
4751
4752
    /**
4753
     * Test for the updateContent() method.
4754
     *
4755
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForUpdate
4756
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForUpdate
4757
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContent
4758
     * @dataProvider providerForTestUpdateContentThrowsContentValidationExceptionFieldDefinition
4759
     */
4760
    public function testUpdateContentThrowsContentValidationExceptionFieldDefinition($initialLanguageCode, $structFields)
4761
    {
4762
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\ContentValidationException::class);
4763
        $this->expectExceptionMessage('Field definition \'identifier\' does not exist in given ContentType');
4764
4765
        $this->assertForUpdateContentContentValidationException(
4766
            $initialLanguageCode,
4767
            $structFields,
4768
            []
4769
        );
4770
    }
4771
4772 View Code Duplication
    public function providerForTestUpdateContentThrowsContentValidationExceptionTranslation()
4773
    {
4774
        return [
4775
            [
4776
                'eng-US',
4777
                [
4778
                    new Field(
4779
                        [
4780
                            'fieldDefIdentifier' => 'identifier',
4781
                            'value' => 'newValue',
4782
                            'languageCode' => 'eng-US',
4783
                        ]
4784
                    ),
4785
                ],
4786
            ],
4787
        ];
4788
    }
4789
4790
    /**
4791
     * Test for the updateContent() method.
4792
     *
4793
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForUpdate
4794
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForUpdate
4795
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContent
4796
     * @dataProvider providerForTestUpdateContentThrowsContentValidationExceptionTranslation
4797
     */
4798 View Code Duplication
    public function testUpdateContentThrowsContentValidationExceptionTranslation($initialLanguageCode, $structFields)
4799
    {
4800
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\ContentValidationException::class);
4801
        $this->expectExceptionMessage('A value is set for non translatable field definition \'identifier\' with language \'eng-US\'');
4802
4803
        $fieldDefinitions = [
4804
            new FieldDefinition(
4805
                [
4806
                    'id' => 'fieldDefinitionId1',
4807
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
4808
                    'isTranslatable' => false,
4809
                    'identifier' => 'identifier',
4810
                    'isRequired' => false,
4811
                    'defaultValue' => self::EMPTY_FIELD_VALUE,
4812
                ]
4813
            ),
4814
        ];
4815
4816
        $this->assertForUpdateContentContentValidationException(
4817
            $initialLanguageCode,
4818
            $structFields,
4819
            $fieldDefinitions
4820
        );
4821
    }
4822
4823
    public function assertForTestUpdateContentRequiredField(
4824
        $initialLanguageCode,
4825
        $structFields,
4826
        $existingFields,
4827
        $fieldDefinitions
4828
    ) {
4829
        $repositoryMock = $this->getRepositoryMock();
4830
        $permissionResolver = $this->getPermissionResolverMock();
4831
        $mockedService = $this->getPartlyMockedContentService(['loadContent']);
4832
        /** @var \PHPUnit\Framework\MockObject\MockObject $languageHandlerMock */
4833
        $languageHandlerMock = $this->getPersistenceMock()->contentLanguageHandler();
4834
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
4835
        $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...
4836
        $fieldTypeMock = $this->createMock(SPIFieldType::class);
4837
        $existingLanguageCodes = array_map(
4838
            function (Field $field) {
4839
                return $field->languageCode;
4840
            },
4841
            $existingFields
4842
        );
4843
        $versionInfo = new VersionInfo(
4844
            [
4845
                'contentInfo' => new ContentInfo(
4846
                    [
4847
                        'id' => 42,
4848
                        'contentTypeId' => 24,
4849
                        'mainLanguageCode' => 'eng-GB',
4850
                    ]
4851
                ),
4852
                'versionNo' => 7,
4853
                'languageCodes' => $existingLanguageCodes,
4854
                'status' => VersionInfo::STATUS_DRAFT,
4855
            ]
4856
        );
4857
        $content = new Content(
4858
            [
4859
                'versionInfo' => $versionInfo,
4860
                'internalFields' => $existingFields,
4861
            ]
4862
        );
4863
        $contentType = new ContentType(['fieldDefinitions' => $fieldDefinitions]);
4864
4865
        $languageHandlerMock->expects($this->any())
4866
            ->method('loadByLanguageCode')
4867
            ->with($this->isType('string'))
4868
            ->will(
4869
                $this->returnCallback(
4870
                    function () {
4871
                        return new Language(['id' => 4242]);
4872
                    }
4873
                )
4874
            );
4875
4876
        $mockedService->expects($this->once())
4877
            ->method('loadContent')
4878
            ->with(
4879
                $this->equalTo(42),
4880
                $this->equalTo(null),
4881
                $this->equalTo(7)
4882
            )->will(
4883
                $this->returnValue($content)
4884
            );
4885
4886
        $permissionResolver->expects($this->once())
4887
            ->method('canUser')
4888
            ->with(
4889
                $this->equalTo('content'),
4890
                $this->equalTo('edit'),
4891
                $this->equalTo($content),
4892
                $this->isType('array')
4893
            )->will($this->returnValue(true));
4894
4895
        $contentTypeServiceMock->expects($this->once())
4896
            ->method('loadContentType')
4897
            ->with($this->equalTo(24))
4898
            ->will($this->returnValue($contentType));
4899
4900
        $repositoryMock->expects($this->once())
4901
            ->method('getContentTypeService')
4902
            ->will($this->returnValue($contentTypeServiceMock));
4903
4904
        $fieldTypeMock->expects($this->any())
4905
            ->method('acceptValue')
4906
            ->will(
4907
                $this->returnCallback(
4908
                    function ($valueString) {
4909
                        return new ValueStub($valueString);
4910
                    }
4911
                )
4912
            );
4913
4914
        $emptyValue = self::EMPTY_FIELD_VALUE;
4915
        $fieldTypeMock->expects($this->any())
4916
            ->method('isEmptyValue')
4917
            ->will(
4918
                $this->returnCallback(
4919
                    function (ValueStub $value) use ($emptyValue) {
4920
                        return $emptyValue === (string)$value;
4921
                    }
4922
                )
4923
            );
4924
4925
        $fieldTypeMock->expects($this->any())
4926
            ->method('validate')
4927
            ->with(
4928
                $this->isInstanceOf(APIFieldDefinition::class),
4929
                $this->isInstanceOf(Value::class)
4930
            );
4931
4932
        $this->getFieldTypeRegistryMock()->expects($this->any())
4933
            ->method('getFieldType')
4934
            ->will($this->returnValue($fieldTypeMock));
4935
4936
        $contentUpdateStruct = new ContentUpdateStruct(
4937
            [
4938
                'fields' => $structFields,
4939
                'initialLanguageCode' => $initialLanguageCode,
4940
            ]
4941
        );
4942
4943
        return [$content->versionInfo, $contentUpdateStruct];
4944
    }
4945
4946 View Code Duplication
    public function providerForTestUpdateContentRequiredField()
4947
    {
4948
        return [
4949
            [
4950
                'eng-US',
4951
                [
4952
                    new Field(
4953
                        [
4954
                            'fieldDefIdentifier' => 'identifier',
4955
                            'value' => self::EMPTY_FIELD_VALUE,
4956
                            'languageCode' => null,
4957
                        ]
4958
                    ),
4959
                ],
4960
                'identifier',
4961
                'eng-US',
4962
            ],
4963
        ];
4964
    }
4965
4966
    /**
4967
     * Test for the updateContent() method.
4968
     *
4969
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForUpdate
4970
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForUpdate
4971
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContent
4972
     * @dataProvider providerForTestUpdateContentRequiredField
4973
     */
4974
    public function testUpdateContentRequiredField(
4975
        $initialLanguageCode,
4976
        $structFields,
4977
        $identifier,
4978
        $languageCode
4979
    ) {
4980
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\ContentFieldValidationException::class);
4981
4982
        $existingFields = [
4983
            new Field(
4984
                [
4985
                    'id' => '100',
4986
                    'fieldDefIdentifier' => 'identifier',
4987
                    'value' => 'initialValue',
4988
                    'languageCode' => 'eng-GB',
4989
                ]
4990
            ),
4991
        ];
4992
        $fieldDefinitions = [
4993
            new FieldDefinition(
4994
                [
4995
                    'id' => 'fieldDefinitionId',
4996
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
4997
                    'isTranslatable' => true,
4998
                    'identifier' => 'identifier',
4999
                    'isRequired' => true,
5000
                    'defaultValue' => 'defaultValue',
5001
                ]
5002
            ),
5003
        ];
5004
        list($versionInfo, $contentUpdateStruct) =
5005
            $this->assertForTestUpdateContentRequiredField(
5006
                $initialLanguageCode,
5007
                $structFields,
5008
                $existingFields,
5009
                $fieldDefinitions
5010
            );
5011
5012
        try {
5013
            $this->partlyMockedContentService->updateContent($versionInfo, $contentUpdateStruct);
5014
        } catch (ContentValidationException $e) {
5015
            $this->assertEquals(
5016
                "Value for required field definition '{$identifier}' with language '{$languageCode}' is empty",
5017
                $e->getMessage()
5018
            );
5019
5020
            throw $e;
5021
        }
5022
    }
5023
5024
    public function assertForTestUpdateContentThrowsContentFieldValidationException(
5025
        $initialLanguageCode,
5026
        $structFields,
5027
        $existingFields,
5028
        $fieldDefinitions
5029
    ) {
5030
        $repositoryMock = $this->getRepositoryMock();
5031
        $permissionResolverMock = $this->getPermissionResolverMock();
5032
        $mockedService = $this->getPartlyMockedContentService(['loadContent']);
5033
        /** @var \PHPUnit\Framework\MockObject\MockObject $languageHandlerMock */
5034
        $languageHandlerMock = $this->getPersistenceMock()->contentLanguageHandler();
5035
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
5036
        $fieldTypeMock = $this->createMock(SPIFieldType::class);
5037
        $existingLanguageCodes = array_map(
5038
            function (Field $field) {
5039
                return $field->languageCode;
5040
            },
5041
            $existingFields
5042
        );
5043
        $languageCodes = $this->determineLanguageCodesForUpdate(
5044
            $initialLanguageCode,
5045
            $structFields,
5046
            $existingLanguageCodes
5047
        );
5048
        $versionInfo = new VersionInfo(
5049
            [
5050
                'contentInfo' => new ContentInfo(
5051
                    [
5052
                        'id' => 42,
5053
                        'contentTypeId' => 24,
5054
                        'mainLanguageCode' => 'eng-GB',
5055
                    ]
5056
                ),
5057
                'versionNo' => 7,
5058
                'languageCodes' => $existingLanguageCodes,
5059
                'status' => VersionInfo::STATUS_DRAFT,
5060
            ]
5061
        );
5062
        $content = new Content(
5063
            [
5064
                'versionInfo' => $versionInfo,
5065
                'internalFields' => $existingFields,
5066
            ]
5067
        );
5068
        $contentType = new ContentType(['fieldDefinitions' => $fieldDefinitions]);
5069
5070
        $languageHandlerMock->expects($this->any())
5071
            ->method('loadByLanguageCode')
5072
            ->with($this->isType('string'))
5073
            ->will(
5074
                $this->returnCallback(
5075
                    function () {
5076
                        return new Language(['id' => 4242]);
5077
                    }
5078
                )
5079
            );
5080
5081
        $mockedService->expects($this->once())
5082
            ->method('loadContent')
5083
            ->with(
5084
                $this->equalTo(42),
5085
                $this->equalTo(null),
5086
                $this->equalTo(7)
5087
            )->will(
5088
                $this->returnValue($content)
5089
            );
5090
5091
        $permissionResolverMock->expects($this->once())
5092
            ->method('canUser')
5093
            ->with(
5094
                $this->equalTo('content'),
5095
                $this->equalTo('edit'),
5096
                $this->equalTo($content),
5097
                $this->isType('array')
5098
            )->will($this->returnValue(true));
5099
5100
        $contentTypeServiceMock->expects($this->once())
5101
            ->method('loadContentType')
5102
            ->with($this->equalTo(24))
5103
            ->will($this->returnValue($contentType));
5104
5105
        $repositoryMock->expects($this->once())
5106
            ->method('getContentTypeService')
5107
            ->will($this->returnValue($contentTypeServiceMock));
5108
5109
        $fieldValues = $this->determineValuesForUpdate(
5110
            $initialLanguageCode,
5111
            $structFields,
5112
            $content,
5113
            $fieldDefinitions,
5114
            $languageCodes
5115
        );
5116
        $allFieldErrors = [];
5117
        $emptyValue = self::EMPTY_FIELD_VALUE;
5118
5119
        $fieldTypeMock->expects($this->exactly(count($fieldValues) * count($languageCodes)))
5120
            ->method('acceptValue')
5121
            ->will(
5122
                $this->returnCallback(
5123
                    function ($valueString) {
5124
                        return new ValueStub($valueString);
5125
                    }
5126
                )
5127
            );
5128
5129
        $fieldTypeMock->expects($this->exactly(count($fieldValues) * count($languageCodes)))
5130
            ->method('isEmptyValue')
5131
            ->will(
5132
                $this->returnCallback(
5133
                    function (ValueStub $value) use ($emptyValue) {
5134
                        return $emptyValue === (string)$value;
5135
                    }
5136
                )
5137
            );
5138
5139
        $fieldTypeMock
5140
            ->expects($this->any())
5141
            ->method('validate')
5142
            ->willReturnArgument(1);
5143
5144
        $this->getFieldTypeRegistryMock()->expects($this->any())
5145
            ->method('getFieldType')
5146
            ->will($this->returnValue($fieldTypeMock));
5147
5148
        $contentUpdateStruct = new ContentUpdateStruct(
5149
            [
5150
                'fields' => $structFields,
5151
                'initialLanguageCode' => $initialLanguageCode,
5152
            ]
5153
        );
5154
5155
        return [$content->versionInfo, $contentUpdateStruct, $allFieldErrors];
5156
    }
5157
5158
    public function providerForTestUpdateContentThrowsContentFieldValidationException()
5159
    {
5160
        $allFieldErrors = [
5161
            [
5162
                'fieldDefinitionId1' => [
5163
                    'eng-GB' => 'newValue1-eng-GB',
5164
                    'eng-US' => 'newValue1-eng-GB',
5165
                ],
5166
                'fieldDefinitionId2' => [
5167
                    'eng-GB' => 'initialValue2',
5168
                ],
5169
                'fieldDefinitionId3' => [
5170
                    'eng-GB' => 'initialValue3',
5171
                    'eng-US' => 'initialValue3',
5172
                ],
5173
                'fieldDefinitionId4' => [
5174
                    'eng-GB' => 'initialValue4',
5175
                    'eng-US' => 'newValue4',
5176
                ],
5177
            ],
5178
            [
5179
                'fieldDefinitionId1' => [
5180
                    'eng-GB' => 'newValue1-eng-GB',
5181
                    'eng-US' => 'newValue1-eng-GB',
5182
                ],
5183
                'fieldDefinitionId2' => [
5184
                    'eng-GB' => 'initialValue2',
5185
                ],
5186
                'fieldDefinitionId3' => [
5187
                    'eng-GB' => 'initialValue3',
5188
                    'eng-US' => 'initialValue3',
5189
                ],
5190
                'fieldDefinitionId4' => [
5191
                    'eng-GB' => 'initialValue4',
5192
                    'eng-US' => 'newValue4',
5193
                ],
5194
            ],
5195
            [
5196
                'fieldDefinitionId1' => [
5197
                    'eng-GB' => 'newValue1-eng-GB',
5198
                    'eng-US' => 'newValue1-eng-GB',
5199
                ],
5200
                'fieldDefinitionId2' => [
5201
                    'eng-GB' => 'initialValue2',
5202
                    'eng-US' => 'newValue2',
5203
                ],
5204
                'fieldDefinitionId3' => [
5205
                    'eng-GB' => 'initialValue3',
5206
                    'eng-US' => 'initialValue3',
5207
                ],
5208
                'fieldDefinitionId4' => [
5209
                    'eng-GB' => 'initialValue4',
5210
                    'eng-US' => 'defaultValue4',
5211
                ],
5212
            ],
5213
            [
5214
                'fieldDefinitionId1' => [
5215
                    'eng-GB' => 'newValue1-eng-GB',
5216
                    'eng-US' => 'newValue1-eng-GB',
5217
                ],
5218
                'fieldDefinitionId2' => [
5219
                    'eng-GB' => 'initialValue2',
5220
                    'eng-US' => 'newValue2',
5221
                ],
5222
                'fieldDefinitionId3' => [
5223
                    'eng-GB' => 'initialValue3',
5224
                    'eng-US' => 'initialValue3',
5225
                ],
5226
                'fieldDefinitionId4' => [
5227
                    'eng-GB' => 'initialValue4',
5228
                    'eng-US' => 'defaultValue4',
5229
                ],
5230
            ],
5231
            [
5232
                'fieldDefinitionId1' => [
5233
                    'eng-GB' => 'newValue1-eng-GB',
5234
                    'ger-DE' => '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
                    'ger-DE' => 'initialValue3',
5244
                    'eng-US' => 'initialValue3',
5245
                ],
5246
                'fieldDefinitionId4' => [
5247
                    'eng-GB' => 'initialValue4',
5248
                    'eng-US' => 'defaultValue4',
5249
                    'ger-DE' => 'defaultValue4',
5250
                ],
5251
            ],
5252
            [
5253
                'fieldDefinitionId1' => [
5254
                    'eng-US' => 'newValue1-eng-GB',
5255
                    'ger-DE' => 'newValue1-eng-GB',
5256
                ],
5257
                'fieldDefinitionId2' => [
5258
                    'eng-US' => 'newValue2',
5259
                ],
5260
                'fieldDefinitionId3' => [
5261
                    'ger-DE' => 'initialValue3',
5262
                    'eng-US' => 'initialValue3',
5263
                ],
5264
                'fieldDefinitionId4' => [
5265
                    'ger-DE' => 'defaultValue4',
5266
                    'eng-US' => 'defaultValue4',
5267
                ],
5268
            ],
5269
        ];
5270
5271
        $data = $this->providerForTestUpdateContentNonRedundantFieldSetComplex();
5272
        $count = count($data);
5273
        for ($i = 0; $i < $count; ++$i) {
5274
            $data[$i][] = $allFieldErrors[$i];
5275
        }
5276
5277
        return $data;
5278
    }
5279
5280
    /**
5281
     * Test for the updateContent() method.
5282
     *
5283
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForUpdate
5284
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForUpdate
5285
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContent
5286
     * @dataProvider providerForTestUpdateContentThrowsContentFieldValidationException
5287
     */
5288 View Code Duplication
    public function testUpdateContentThrowsContentFieldValidationException($initialLanguageCode, $structFields, $spiField, $allFieldErrors)
0 ignored issues
show
Unused Code introduced by
The parameter $spiField is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
5289
    {
5290
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\ContentFieldValidationException::class);
5291
        $this->expectExceptionMessage('Content fields did not validate');
5292
5293
        list($existingFields, $fieldDefinitions) = $this->fixturesForTestUpdateContentNonRedundantFieldSetComplex();
5294
        list($versionInfo, $contentUpdateStruct) =
5295
            $this->assertForTestUpdateContentThrowsContentFieldValidationException(
5296
                $initialLanguageCode,
5297
                $structFields,
5298
                $existingFields,
5299
                $fieldDefinitions
5300
            );
5301
5302
        try {
5303
            $this->partlyMockedContentService->updateContent($versionInfo, $contentUpdateStruct);
5304
        } catch (ContentFieldValidationException $e) {
5305
            $this->assertEquals($allFieldErrors, $e->getFieldErrors());
5306
            throw $e;
5307
        }
5308
    }
5309
5310
    /**
5311
     * Test for the updateContent() method.
5312
     *
5313
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForUpdate
5314
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForUpdate
5315
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContent
5316
     */
5317
    public function testUpdateContentTransactionRollback()
5318
    {
5319
        $this->expectException(\Exception::class);
5320
        $this->expectExceptionMessage('Store failed');
5321
5322
        $existingFields = [
5323
            new Field(
5324
                [
5325
                    'id' => '100',
5326
                    'fieldDefIdentifier' => 'identifier',
5327
                    'value' => 'initialValue',
5328
                    'languageCode' => 'eng-GB',
5329
                ]
5330
            ),
5331
        ];
5332
5333
        $fieldDefinitions = [
5334
            new FieldDefinition(
5335
                [
5336
                    'id' => 'fieldDefinitionId',
5337
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
5338
                    'isTranslatable' => false,
5339
                    'identifier' => 'identifier',
5340
                    'isRequired' => false,
5341
                    'defaultValue' => 'defaultValue',
5342
                ]
5343
            ),
5344
        ];
5345
5346
        // Setup a simple case that will pass
5347
        list($versionInfo, $contentUpdateStruct) = $this->assertForTestUpdateContentNonRedundantFieldSet(
5348
            'eng-US',
5349
            [],
5350
            [],
5351
            $existingFields,
5352
            $fieldDefinitions,
5353
            // Do not execute test
5354
            false
5355
        );
5356
5357
        $repositoryMock = $this->getRepositoryMock();
5358
        $repositoryMock->expects($this->never())->method('commit');
5359
        $repositoryMock->expects($this->once())->method('rollback');
5360
5361
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandlerMock */
5362
        $contentHandlerMock = $this->getPersistenceMock()->contentHandler();
5363
        $contentHandlerMock->expects($this->once())
5364
            ->method('updateContent')
5365
            ->with(
5366
                $this->anything(),
5367
                $this->anything(),
5368
                $this->anything()
5369
            )->will($this->throwException(new \Exception('Store failed')));
5370
5371
        // Execute
5372
        $this->partlyMockedContentService->updateContent($versionInfo, $contentUpdateStruct);
5373
    }
5374
5375
    /**
5376
     * Test for the copyContent() method.
5377
     *
5378
     * @covers \eZ\Publish\Core\Repository\ContentService::copyContent
5379
     */
5380
    public function testCopyContentThrowsUnauthorizedException()
5381
    {
5382
        $this->expectException(\eZ\Publish\Core\Base\Exceptions\UnauthorizedException::class);
5383
5384
        $repository = $this->getRepositoryMock();
5385
        $contentService = $this->getPartlyMockedContentService(['internalLoadContentInfo']);
5386
        $contentInfo = $this->createMock(APIContentInfo::class);
5387
        $locationCreateStruct = new LocationCreateStruct();
5388
        $location = new Location(['id' => $locationCreateStruct->parentLocationId]);
5389
        $locationServiceMock = $this->getLocationServiceMock();
5390
5391
        $repository->expects($this->once())
5392
            ->method('getLocationService')
5393
            ->will($this->returnValue($locationServiceMock))
5394
        ;
5395
5396
        $locationServiceMock->expects($this->once())
5397
            ->method('loadLocation')
5398
            ->with(
5399
                $locationCreateStruct->parentLocationId
5400
            )
5401
            ->will($this->returnValue($location))
5402
        ;
5403
5404
        $contentInfo->expects($this->any())
5405
            ->method('__get')
5406
            ->with('sectionId')
5407
            ->will($this->returnValue(42));
5408
5409
        $repository->expects($this->once())
5410
            ->method('canUser')
5411
            ->with(
5412
                'content',
5413
                'create',
5414
                $contentInfo,
5415
                [$location]
5416
            )
5417
            ->will($this->returnValue(false));
5418
5419
        /* @var \eZ\Publish\API\Repository\Values\Content\ContentInfo $contentInfo */
5420
        $contentService->copyContent($contentInfo, $locationCreateStruct);
5421
    }
5422
5423
    /**
5424
     * Test for the copyContent() method.
5425
     *
5426
     * @covers \eZ\Publish\Core\Repository\ContentService::copyContent
5427
     * @covers \eZ\Publish\Core\Repository\ContentService::getDefaultObjectStates
5428
     * @covers \eZ\Publish\Core\Repository\ContentService::internalPublishVersion
5429
     */
5430
    public function testCopyContent()
5431
    {
5432
        $repositoryMock = $this->getRepositoryMock();
5433
        $contentService = $this->getPartlyMockedContentService([
5434
            'internalLoadContentInfo',
5435
            'internalLoadContent',
5436
            'getUnixTimestamp',
5437
        ]);
5438
        $locationServiceMock = $this->getLocationServiceMock();
5439
        $contentInfoMock = $this->createMock(APIContentInfo::class);
5440
        $locationCreateStruct = new LocationCreateStruct();
5441
        $location = new Location(['id' => $locationCreateStruct->parentLocationId]);
5442
        $user = $this->getStubbedUser(14);
5443
5444
        $permissionResolverMock = $this->getPermissionResolverMock();
5445
5446
        $permissionResolverMock
5447
            ->method('getCurrentUserReference')
5448
            ->willReturn($user);
5449
5450
        $repositoryMock
5451
            ->method('getPermissionResolver')
5452
            ->willReturn($permissionResolverMock);
5453
5454
        $repositoryMock->expects($this->exactly(3))
5455
            ->method('getLocationService')
5456
            ->will($this->returnValue($locationServiceMock));
5457
5458
        $locationServiceMock->expects($this->once())
5459
            ->method('loadLocation')
5460
            ->with($locationCreateStruct->parentLocationId)
5461
            ->will($this->returnValue($location))
5462
        ;
5463
5464
        $contentInfoMock->expects($this->any())
5465
            ->method('__get')
5466
            ->with('id')
5467
            ->will($this->returnValue(42));
5468
        $versionInfoMock = $this->createMock(APIVersionInfo::class);
5469
5470
        $versionInfoMock->expects($this->any())
5471
            ->method('__get')
5472
            ->will(
5473
                $this->returnValueMap(
5474
                    [
5475
                        ['versionNo', 123],
5476
                    ]
5477
                )
5478
            );
5479
5480
        $versionInfoMock->expects($this->once())
5481
            ->method('isDraft')
5482
            ->willReturn(true);
5483
5484
        $versionInfoMock->expects($this->once())
5485
            ->method('getContentInfo')
5486
            ->will($this->returnValue($contentInfoMock));
5487
5488
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandlerMock */
5489
        $contentHandlerMock = $this->getPersistenceMock()->contentHandler();
5490
        $domainMapperMock = $this->getDomainMapperMock();
5491
5492
        $repositoryMock->expects($this->once())->method('beginTransaction');
5493
        $repositoryMock->expects($this->once())->method('commit');
5494
        $repositoryMock
5495
            ->method('canUser')
5496
            ->willReturnMap(
5497
                [
5498
                    ['content', 'create', $contentInfoMock, [$location], true],
5499
                    ['content', 'manage_locations', $contentInfoMock, [$location], true],
5500
                ]
5501
            );
5502
5503
        $spiContentInfo = new SPIContentInfo(['id' => 42]);
5504
        $spiVersionInfo = new SPIVersionInfo(
5505
            [
5506
                'contentInfo' => $spiContentInfo,
5507
                'creationDate' => 123456,
5508
            ]
5509
        );
5510
        $spiContent = new SPIContent(['versionInfo' => $spiVersionInfo]);
5511
        $contentHandlerMock->expects($this->once())
5512
            ->method('copy')
5513
            ->with(42, null)
5514
            ->will($this->returnValue($spiContent));
5515
5516
        $this->mockGetDefaultObjectStates();
5517
        $this->mockSetDefaultObjectStates();
5518
5519
        $domainMapperMock->expects($this->once())
5520
            ->method('buildVersionInfoDomainObject')
5521
            ->with($spiVersionInfo)
5522
            ->will($this->returnValue($versionInfoMock));
5523
5524
        /* @var \eZ\Publish\API\Repository\Values\Content\VersionInfo $versionInfoMock */
5525
        $content = $this->mockPublishVersion(123456, 126666);
5526
        $locationServiceMock->expects($this->once())
5527
            ->method('createLocation')
5528
            ->with(
5529
                $content->getVersionInfo()->getContentInfo(),
5530
                $locationCreateStruct
5531
            );
5532
5533
        $contentService->expects($this->once())
5534
            ->method('internalLoadContent')
5535
            ->with(
5536
                $content->id
5537
            )
5538
            ->will($this->returnValue($content));
5539
5540
        $contentService->expects($this->once())
5541
            ->method('getUnixTimestamp')
5542
            ->will($this->returnValue(126666));
5543
5544
        /* @var \eZ\Publish\API\Repository\Values\Content\ContentInfo $contentInfoMock */
5545
        $contentService->copyContent($contentInfoMock, $locationCreateStruct, null);
5546
    }
5547
5548
    /**
5549
     * Test for the copyContent() method.
5550
     *
5551
     * @covers \eZ\Publish\Core\Repository\ContentService::copyContent
5552
     * @covers \eZ\Publish\Core\Repository\ContentService::getDefaultObjectStates
5553
     * @covers \eZ\Publish\Core\Repository\ContentService::internalPublishVersion
5554
     */
5555
    public function testCopyContentWithVersionInfo()
5556
    {
5557
        $repositoryMock = $this->getRepositoryMock();
5558
        $contentService = $this->getPartlyMockedContentService([
5559
            'internalLoadContentInfo',
5560
            'internalLoadContent',
5561
            'getUnixTimestamp',
5562
        ]);
5563
        $locationServiceMock = $this->getLocationServiceMock();
5564
        $contentInfoMock = $this->createMock(APIContentInfo::class);
5565
        $locationCreateStruct = new LocationCreateStruct();
5566
        $location = new Location(['id' => $locationCreateStruct->parentLocationId]);
5567
        $user = $this->getStubbedUser(14);
5568
5569
        $permissionResolverMock = $this->getPermissionResolverMock();
5570
5571
        $permissionResolverMock
5572
            ->method('getCurrentUserReference')
5573
            ->willReturn($user);
5574
5575
        $repositoryMock
5576
            ->method('getPermissionResolver')
5577
            ->willReturn($permissionResolverMock);
5578
5579
        $repositoryMock->expects($this->exactly(3))
5580
            ->method('getLocationService')
5581
            ->will($this->returnValue($locationServiceMock));
5582
5583
        $locationServiceMock->expects($this->once())
5584
            ->method('loadLocation')
5585
            ->with($locationCreateStruct->parentLocationId)
5586
            ->will($this->returnValue($location))
5587
        ;
5588
5589
        $contentInfoMock->expects($this->any())
5590
            ->method('__get')
5591
            ->with('id')
5592
            ->will($this->returnValue(42));
5593
        $versionInfoMock = $this->createMock(APIVersionInfo::class);
5594
5595
        $versionInfoMock->expects($this->any())
5596
            ->method('__get')
5597
            ->will(
5598
                $this->returnValueMap(
5599
                    [
5600
                        ['versionNo', 123],
5601
                    ]
5602
                )
5603
            );
5604
        $versionInfoMock->expects($this->once())
5605
            ->method('isDraft')
5606
            ->willReturn(true);
5607
        $versionInfoMock->expects($this->once())
5608
            ->method('getContentInfo')
5609
            ->will($this->returnValue($contentInfoMock));
5610
5611
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandlerMock */
5612
        $contentHandlerMock = $this->getPersistenceMock()->contentHandler();
5613
        $domainMapperMock = $this->getDomainMapperMock();
5614
5615
        $repositoryMock->expects($this->once())->method('beginTransaction');
5616
        $repositoryMock->expects($this->once())->method('commit');
5617
        $repositoryMock
5618
            ->method('canUser')
5619
            ->willReturnMap(
5620
                [
5621
                    ['content', 'create', $contentInfoMock, [$location], true],
5622
                    ['content', 'manage_locations', $contentInfoMock, [$location], true],
5623
                ]
5624
            );
5625
5626
        $spiContentInfo = new SPIContentInfo(['id' => 42]);
5627
        $spiVersionInfo = new SPIVersionInfo(
5628
            [
5629
                'contentInfo' => $spiContentInfo,
5630
                'creationDate' => 123456,
5631
            ]
5632
        );
5633
        $spiContent = new SPIContent(['versionInfo' => $spiVersionInfo]);
5634
        $contentHandlerMock->expects($this->once())
5635
            ->method('copy')
5636
            ->with(42, 123)
5637
            ->will($this->returnValue($spiContent));
5638
5639
        $this->mockGetDefaultObjectStates();
5640
        $this->mockSetDefaultObjectStates();
5641
5642
        $domainMapperMock->expects($this->once())
5643
            ->method('buildVersionInfoDomainObject')
5644
            ->with($spiVersionInfo)
5645
            ->will($this->returnValue($versionInfoMock));
5646
5647
        /* @var \eZ\Publish\API\Repository\Values\Content\VersionInfo $versionInfoMock */
5648
        $content = $this->mockPublishVersion(123456, 126666);
5649
        $locationServiceMock->expects($this->once())
5650
            ->method('createLocation')
5651
            ->with(
5652
                $content->getVersionInfo()->getContentInfo(),
5653
                $locationCreateStruct
5654
            );
5655
5656
        $contentService->expects($this->once())
5657
            ->method('internalLoadContent')
5658
            ->with(
5659
                $content->id
5660
            )
5661
            ->will($this->returnValue($content));
5662
5663
        $contentService->expects($this->once())
5664
            ->method('getUnixTimestamp')
5665
            ->will($this->returnValue(126666));
5666
5667
        /* @var \eZ\Publish\API\Repository\Values\Content\ContentInfo $contentInfoMock */
5668
        $contentService->copyContent($contentInfoMock, $locationCreateStruct, $versionInfoMock);
5669
    }
5670
5671
    /**
5672
     * Test for the copyContent() method.
5673
     *
5674
     * @covers \eZ\Publish\Core\Repository\ContentService::copyContent
5675
     * @covers \eZ\Publish\Core\Repository\ContentService::getDefaultObjectStates
5676
     * @covers \eZ\Publish\Core\Repository\ContentService::internalPublishVersion
5677
     */
5678
    public function testCopyContentWithRollback()
5679
    {
5680
        $this->expectException(\Exception::class);
5681
        $this->expectExceptionMessage('Handler threw an exception');
5682
5683
        $repositoryMock = $this->getRepositoryMock();
5684
        $contentService = $this->getPartlyMockedContentService();
5685
        /** @var \PHPUnit\Framework\MockObject\MockObject $contentHandlerMock */
5686
        $contentHandlerMock = $this->getPersistenceMock()->contentHandler();
5687
        $locationCreateStruct = new LocationCreateStruct();
5688
        $location = new Location(['id' => $locationCreateStruct->parentLocationId]);
5689
        $locationServiceMock = $this->getLocationServiceMock();
5690
        $user = $this->getStubbedUser(14);
5691
5692
        $permissionResolverMock = $this->getPermissionResolverMock();
5693
5694
        $permissionResolverMock
5695
            ->method('getCurrentUserReference')
5696
            ->willReturn($user);
5697
5698
        $repositoryMock
5699
            ->method('getPermissionResolver')
5700
            ->willReturn($permissionResolverMock);
5701
5702
        $repositoryMock->expects($this->once())
5703
            ->method('getLocationService')
5704
            ->will($this->returnValue($locationServiceMock))
5705
        ;
5706
5707
        $locationServiceMock->expects($this->once())
5708
            ->method('loadLocation')
5709
            ->with($locationCreateStruct->parentLocationId)
5710
            ->will($this->returnValue($location))
5711
        ;
5712
5713
        $contentInfoMock = $this->createMock(APIContentInfo::class);
5714
        $contentInfoMock->expects($this->any())
5715
            ->method('__get')
5716
            ->with('id')
5717
            ->will($this->returnValue(42));
5718
5719
        $this->mockGetDefaultObjectStates();
5720
5721
        $repositoryMock->expects($this->once())->method('beginTransaction');
5722
        $repositoryMock->expects($this->once())->method('rollback');
5723
        $repositoryMock
5724
            ->method('canUser')
5725
            ->willReturnMap(
5726
                [
5727
                    ['content', 'create', $contentInfoMock, [$location], true],
5728
                    ['content', 'manage_locations', $contentInfoMock, [$location], true],
5729
                ]
5730
            );
5731
5732
        $contentHandlerMock->expects($this->once())
5733
            ->method('copy')
5734
            ->with(42, null)
5735
            ->will($this->throwException(new Exception('Handler threw an exception')));
5736
5737
        /* @var \eZ\Publish\API\Repository\Values\Content\ContentInfo $contentInfoMock */
5738
        $contentService->copyContent($contentInfoMock, $locationCreateStruct, null);
5739
    }
5740
5741
    /**
5742
     * Reusable method for setting exceptions on buildContentDomainObject usage.
5743
     *
5744
     * Plain usage as in when content type is loaded directly.
5745
     *
5746
     * @param \eZ\Publish\SPI\Persistence\Content $spiContent
5747
     * @param array $translations
5748
     * @param bool $useAlwaysAvailable
5749
     *
5750
     * @return \PHPUnit\Framework\MockObject\MockObject|\eZ\Publish\API\Repository\Values\Content\Content
5751
     */
5752
    private function mockBuildContentDomainObject(SPIContent $spiContent, array $translations = null, bool $useAlwaysAvailable = null)
5753
    {
5754
        $contentTypeId = $spiContent->versionInfo->contentInfo->contentTypeId;
5755
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
5756
        $repositoryMock = $this->getRepositoryMock();
5757
5758
        $contentType = new ContentType([
5759
            'id' => $contentTypeId,
5760
            'fieldDefinitions' => [],
5761
        ]);
5762
5763
        $repositoryMock->expects($this->once())
5764
            ->method('getContentTypeService')
5765
            ->willReturn($contentTypeServiceMock);
5766
5767
        $contentTypeServiceMock->expects($this->once())
5768
            ->method('loadContentType')
5769
            ->with($this->equalTo($contentTypeId))
5770
            ->willReturn($contentType);
5771
5772
        $content = $this->createMock(APIContent::class);
5773
5774
        $this->getDomainMapperMock()
5775
            ->expects($this->once())
5776
            ->method('buildContentDomainObject')
5777
            ->with($spiContent, $contentType, $translations ?? [], $useAlwaysAvailable)
5778
            ->willReturn($content);
5779
5780
        return $content;
5781
    }
5782
5783
    protected function mockGetDefaultObjectStates()
5784
    {
5785
        /** @var \PHPUnit\Framework\MockObject\MockObject $objectStateHandlerMock */
5786
        $objectStateHandlerMock = $this->getPersistenceMock()->objectStateHandler();
5787
5788
        $objectStateGroups = [
5789
            new SPIObjectStateGroup(['id' => 10]),
5790
            new SPIObjectStateGroup(['id' => 20]),
5791
        ];
5792
5793
        /* @var \PHPUnit\Framework\MockObject\MockObject $objectStateHandlerMock */
5794
        $objectStateHandlerMock->expects($this->once())
5795
            ->method('loadAllGroups')
5796
            ->will($this->returnValue($objectStateGroups));
5797
5798
        $objectStateHandlerMock->expects($this->at(1))
5799
            ->method('loadObjectStates')
5800
            ->with($this->equalTo(10))
5801
            ->will(
5802
                $this->returnValue(
5803
                    [
5804
                        new SPIObjectState(['id' => 11, 'groupId' => 10]),
5805
                        new SPIObjectState(['id' => 12, 'groupId' => 10]),
5806
                    ]
5807
                )
5808
            );
5809
5810
        $objectStateHandlerMock->expects($this->at(2))
5811
            ->method('loadObjectStates')
5812
            ->with($this->equalTo(20))
5813
            ->will(
5814
                $this->returnValue(
5815
                    [
5816
                        new SPIObjectState(['id' => 21, 'groupId' => 20]),
5817
                        new SPIObjectState(['id' => 22, 'groupId' => 20]),
5818
                    ]
5819
                )
5820
            );
5821
    }
5822
5823
    protected function mockSetDefaultObjectStates()
5824
    {
5825
        /** @var \PHPUnit\Framework\MockObject\MockObject $objectStateHandlerMock */
5826
        $objectStateHandlerMock = $this->getPersistenceMock()->objectStateHandler();
5827
5828
        $defaultObjectStates = [
5829
            new SPIObjectState(['id' => 11, 'groupId' => 10]),
5830
            new SPIObjectState(['id' => 21, 'groupId' => 20]),
5831
        ];
5832
        foreach ($defaultObjectStates as $index => $objectState) {
5833
            $objectStateHandlerMock->expects($this->at($index + 3))
5834
                ->method('setContentState')
5835
                ->with(
5836
                    42,
5837
                    $objectState->groupId,
5838
                    $objectState->id
5839
                );
5840
        }
5841
    }
5842
5843
    /**
5844
     * @param int|null $publicationDate
5845
     * @param int|null $modificationDate
5846
     *
5847
     * @return \eZ\Publish\API\Repository\Values\Content\Content
5848
     */
5849
    protected function mockPublishVersion($publicationDate = null, $modificationDate = null)
5850
    {
5851
        $versionInfoMock = $this->createMock(APIVersionInfo::class);
5852
        $contentInfoMock = $this->createMock(APIContentInfo::class);
5853
        /* @var \PHPUnit\Framework\MockObject\MockObject $contentHandlerMock */
5854
        $contentHandlerMock = $this->getPersistenceMock()->contentHandler();
5855
        $metadataUpdateStruct = new SPIMetadataUpdateStruct();
5856
5857
        $spiContent = new SPIContent([
5858
            'versionInfo' => new VersionInfo([
5859
                    'contentInfo' => new ContentInfo(['id' => 42, 'contentTypeId' => 123]),
5860
            ]),
5861
        ]);
5862
5863
        $contentMock = $this->mockBuildContentDomainObject($spiContent);
5864
        $contentMock->expects($this->any())
5865
            ->method('__get')
5866
            ->will(
5867
                $this->returnValueMap(
5868
                    [
5869
                        ['id', 42],
5870
                        ['contentInfo', $contentInfoMock],
5871
                        ['versionInfo', $versionInfoMock],
5872
                    ]
5873
                )
5874
            );
5875
        $contentMock->expects($this->any())
5876
            ->method('getVersionInfo')
5877
            ->will($this->returnValue($versionInfoMock));
5878
        $versionInfoMock->expects($this->any())
5879
            ->method('getContentInfo')
5880
            ->will($this->returnValue($contentInfoMock));
5881
        $versionInfoMock->expects($this->any())
5882
            ->method('__get')
5883
            ->will(
5884
                $this->returnValueMap(
5885
                    [
5886
                        ['languageCodes', ['eng-GB']],
5887
                    ]
5888
                )
5889
            );
5890
        $contentInfoMock->expects($this->any())
5891
            ->method('__get')
5892
            ->will(
5893
                $this->returnValueMap(
5894
                    [
5895
                        ['alwaysAvailable', true],
5896
                        ['mainLanguageCode', 'eng-GB'],
5897
                    ]
5898
                )
5899
            );
5900
5901
        $currentTime = time();
5902
        if ($publicationDate === null && $versionInfoMock->versionNo === 1) {
5903
            $publicationDate = $currentTime;
5904
        }
5905
5906
        // Account for 1 second of test execution time
5907
        $metadataUpdateStruct->publicationDate = $publicationDate;
5908
        $metadataUpdateStruct->modificationDate = $modificationDate ?? $currentTime;
5909
5910
        $contentHandlerMock->expects($this->once())
5911
            ->method('publish')
5912
            ->with(
5913
                42,
5914
                123,
5915
                $metadataUpdateStruct
5916
            )
5917
            ->will($this->returnValue($spiContent));
5918
5919
        /* @var \eZ\Publish\API\Repository\Values\Content\Content $contentMock */
5920
        $this->mockPublishUrlAliasesForContent($contentMock);
5921
5922
        return $contentMock;
5923
    }
5924
5925
    /**
5926
     * @param \eZ\Publish\API\Repository\Values\Content\Content $content
5927
     */
5928
    protected function mockPublishUrlAliasesForContent(APIContent $content)
5929
    {
5930
        $nameSchemaServiceMock = $this->getNameSchemaServiceMock();
5931
        /** @var \PHPUnit\Framework\MockObject\MockObject $urlAliasHandlerMock */
5932
        $urlAliasHandlerMock = $this->getPersistenceMock()->urlAliasHandler();
5933
        $locationServiceMock = $this->getLocationServiceMock();
5934
        $location = $this->createMock(APILocation::class);
5935
5936
        $location->expects($this->at(0))
5937
            ->method('__get')
5938
            ->with('id')
5939
            ->will($this->returnValue(123));
5940
        $location->expects($this->at(1))
5941
            ->method('__get')
5942
            ->with('parentLocationId')
5943
            ->will($this->returnValue(456));
5944
5945
        $urlAliasNames = ['eng-GB' => 'hello'];
5946
        $nameSchemaServiceMock->expects($this->once())
5947
            ->method('resolveUrlAliasSchema')
5948
            ->with($content)
5949
            ->will($this->returnValue($urlAliasNames));
5950
5951
        $locationServiceMock->expects($this->once())
5952
            ->method('loadLocations')
5953
            ->with($content->getVersionInfo()->getContentInfo())
5954
            ->will($this->returnValue([$location]));
5955
5956
        $urlAliasHandlerMock->expects($this->once())
5957
            ->method('publishUrlAliasForLocation')
5958
            ->with(123, 456, 'hello', 'eng-GB', true, true);
5959
5960
        $location->expects($this->at(2))
5961
            ->method('__get')
5962
            ->with('id')
5963
            ->will($this->returnValue(123));
5964
5965
        $location->expects($this->at(3))
5966
            ->method('__get')
5967
            ->with('parentLocationId')
5968
            ->will($this->returnValue(456));
5969
5970
        $urlAliasHandlerMock->expects($this->once())
5971
            ->method('archiveUrlAliasesForDeletedTranslations')
5972
            ->with(123, 456, ['eng-GB']);
5973
    }
5974
5975
    protected $domainMapperMock;
5976
5977
    /**
5978
     * @return \PHPUnit\Framework\MockObject\MockObject|\eZ\Publish\Core\Repository\Helper\DomainMapper
5979
     */
5980
    protected function getDomainMapperMock()
5981
    {
5982
        if (!isset($this->domainMapperMock)) {
5983
            $this->domainMapperMock = $this->createMock(DomainMapper::class);
5984
        }
5985
5986
        return $this->domainMapperMock;
5987
    }
5988
5989
    protected $relationProcessorMock;
5990
5991
    /**
5992
     * @return \PHPUnit\Framework\MockObject\MockObject|\eZ\Publish\Core\Repository\Helper\RelationProcessor
5993
     */
5994
    protected function getRelationProcessorMock()
5995
    {
5996
        if (!isset($this->relationProcessorMock)) {
5997
            $this->relationProcessorMock = $this->createMock(RelationProcessor::class);
5998
        }
5999
6000
        return $this->relationProcessorMock;
6001
    }
6002
6003
    protected $nameSchemaServiceMock;
6004
6005
    /**
6006
     * @return \PHPUnit\Framework\MockObject\MockObject|\eZ\Publish\Core\Repository\Helper\NameSchemaService
6007
     */
6008
    protected function getNameSchemaServiceMock()
6009
    {
6010
        if (!isset($this->nameSchemaServiceMock)) {
6011
            $this->nameSchemaServiceMock = $this->createMock(NameSchemaService::class);
6012
        }
6013
6014
        return $this->nameSchemaServiceMock;
6015
    }
6016
6017
    protected $contentTypeServiceMock;
6018
6019
    /**
6020
     * @return \PHPUnit\Framework\MockObject\MockObject|\eZ\Publish\API\Repository\ContentTypeService
6021
     */
6022
    protected function getContentTypeServiceMock()
6023
    {
6024
        if (!isset($this->contentTypeServiceMock)) {
6025
            $this->contentTypeServiceMock = $this->createMock(APIContentTypeService::class);
6026
        }
6027
6028
        return $this->contentTypeServiceMock;
6029
    }
6030
6031
    protected $locationServiceMock;
6032
6033
    /**
6034
     * @return \PHPUnit\Framework\MockObject\MockObject|\eZ\Publish\API\Repository\LocationService
6035
     */
6036
    protected function getLocationServiceMock()
6037
    {
6038
        if (!isset($this->locationServiceMock)) {
6039
            $this->locationServiceMock = $this->createMock(APILocationService::class);
6040
        }
6041
6042
        return $this->locationServiceMock;
6043
    }
6044
6045
    /** @var \eZ\Publish\Core\Repository\ContentService */
6046
    protected $partlyMockedContentService;
6047
6048
    /**
6049
     * Returns the content service to test with $methods mocked.
6050
     *
6051
     * Injected Repository comes from {@see getRepositoryMock()} and persistence handler from {@see getPersistenceMock()}
6052
     *
6053
     * @param string[] $methods
6054
     *
6055
     * @return \eZ\Publish\Core\Repository\ContentService|\PHPUnit\Framework\MockObject\MockObject
6056
     */
6057
    protected function getPartlyMockedContentService(array $methods = null)
6058
    {
6059
        if (!isset($this->partlyMockedContentService)) {
6060
            $this->partlyMockedContentService = $this->getMockBuilder(ContentService::class)
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->getMockBuilder(\e...), array()))->getMock() of type object<PHPUnit\Framework\MockObject\MockObject> is incompatible with the declared type object<eZ\Publish\Core\Repository\ContentService> of property $partlyMockedContentService.

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

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

Loading history...
Deprecated Code introduced by
The method PHPUnit\Framework\MockOb...ckBuilder::setMethods() has been deprecated with message: https://github.com/sebastianbergmann/phpunit/pull/3687

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

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

Loading history...
6061
                ->setMethods($methods)
6062
                ->setConstructorArgs(
6063
                    [
6064
                        $this->getRepositoryMock(),
6065
                        $this->getPersistenceMock(),
6066
                        $this->getDomainMapperMock(),
6067
                        $this->getRelationProcessorMock(),
6068
                        $this->getNameSchemaServiceMock(),
6069
                        $this->getFieldTypeRegistryMock(),
6070
                        [],
6071
                    ]
6072
                )
6073
                ->getMock();
6074
        }
6075
6076
        return $this->partlyMockedContentService;
6077
    }
6078
6079
    /**
6080
     * @return \eZ\Publish\API\Repository\Repository|\PHPUnit\Framework\MockObject\MockObject
6081
     */
6082
    protected function getRepositoryMock(): Repository
6083
    {
6084
        $repositoryMock = parent::getRepositoryMock();
6085
        $repositoryMock
6086
            ->expects($this->any())
6087
            ->method('getPermissionResolver')
6088
            ->willReturn($this->getPermissionResolverMock());
6089
6090
        return $repositoryMock;
6091
    }
6092
}
6093