Completed
Push — ezp-30696 ( 9bb3ad...3bd812 )
by
unknown
49:02 queued 18:35
created

ContentTest::testInternalLoadContent()   B

Complexity

Conditions 5
Paths 3

Size

Total Lines 42

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
nc 3
nop 5
dl 0
loc 42
rs 8.9368
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()
72
    {
73
        $repositoryMock = $this->getRepositoryMock();
74
        /** @var \eZ\Publish\SPI\Persistence\Handler $persistenceHandlerMock */
75
        $persistenceHandlerMock = $this->getPersistenceMockHandler('Handler');
76
        $domainMapperMock = $this->getDomainMapperMock();
77
        $relationProcessorMock = $this->getRelationProcessorMock();
78
        $nameSchemaServiceMock = $this->getNameSchemaServiceMock();
79
        $fieldTypeRegistryMock = $this->getFieldTypeRegistryMock();
80
        $settings = ['default_version_archive_limit' => 10];
81
82
        $service = new ContentService(
83
            $repositoryMock,
0 ignored issues
show
Bug introduced by
It seems like $repositoryMock defined by $this->getRepositoryMock() on line 73 can also be of type object<PHPUnit\Framework\MockObject\MockObject>; however, eZ\Publish\Core\Reposito...tService::__construct() does only seem to accept object<eZ\Publish\API\Repository\Repository>, maybe add an additional type check?

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

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

    return array();
}

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

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

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

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

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

    return array();
}

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

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

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

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

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

    return array();
}

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

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

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

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

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

    return array();
}

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

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

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

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

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

    return array();
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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