Completed
Push — master ( d9c656...9fc60c )
by André
53:37 queued 39:21
created

ContentTest::testCopyContentWithRollback()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 49
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 35
nc 1
nop 0
dl 0
loc 49
rs 9.2258
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\Values\Content\Language;
12
use eZ\Publish\API\Repository\Values\Content\LocationCreateStruct;
13
use eZ\Publish\Core\Base\Exceptions\ContentFieldValidationException;
14
use eZ\Publish\Core\Base\Exceptions\ContentValidationException;
15
use eZ\Publish\Core\Repository\Tests\Service\Mock\Base as BaseServiceMockTest;
16
use eZ\Publish\Core\Repository\ContentService;
17
use eZ\Publish\Core\Repository\Values\Content\Location;
18
use eZ\Publish\Core\Repository\Values\Content\Content;
19
use eZ\Publish\Core\Repository\Values\Content\ContentCreateStruct;
20
use eZ\Publish\Core\Repository\Values\Content\ContentUpdateStruct;
21
use eZ\Publish\API\Repository\Values\Content\Content as APIContent;
22
use eZ\Publish\Core\Repository\Values\Content\VersionInfo;
23
use eZ\Publish\API\Repository\Values\Content\Field;
24
use eZ\Publish\API\Repository\Values\Content\ContentInfo;
25
use eZ\Publish\Core\Repository\Values\ContentType\ContentType;
26
use eZ\Publish\Core\Repository\Values\ContentType\FieldDefinition;
27
use eZ\Publish\SPI\Persistence\Content\Location as SPILocation;
28
use eZ\Publish\SPI\Persistence\Content as SPIContent;
29
use eZ\Publish\SPI\Persistence\Content\UpdateStruct as SPIContentUpdateStruct;
30
use eZ\Publish\SPI\Persistence\Content\CreateStruct as SPIContentCreateStruct;
31
use eZ\Publish\SPI\Persistence\Content\Field as SPIField;
32
use eZ\Publish\SPI\Persistence\Content\ObjectState\Group as SPIObjectStateGroup;
33
use eZ\Publish\SPI\Persistence\Content\ObjectState as SPIObjectState;
34
use eZ\Publish\SPI\Persistence\Content\VersionInfo as SPIVersionInfo;
35
use eZ\Publish\SPI\Persistence\Content\ContentInfo as SPIContentInfo;
36
use eZ\Publish\SPI\Persistence\Content\MetadataUpdateStruct as SPIMetadataUpdateStruct;
37
use eZ\Publish\Core\Base\Exceptions\NotFoundException;
38
use eZ\Publish\Core\Repository\Values\User\UserReference;
39
use Exception;
40
41
/**
42
 * Mock test case for Content service.
43
 */
44
class ContentTest extends BaseServiceMockTest
45
{
46
    /**
47
     * Represents empty Field Value.
48
     */
49
    const EMPTY_FIELD_VALUE = 'empty';
50
51
    /**
52
     * Test for the __construct() method.
53
     *
54
     * @covers \eZ\Publish\Core\Repository\ContentService::__construct
55
     */
56
    public function testConstructor()
57
    {
58
        $repositoryMock = $this->getRepositoryMock();
59
        /** @var \eZ\Publish\SPI\Persistence\Handler $persistenceHandlerMock */
60
        $persistenceHandlerMock = $this->getPersistenceMockHandler('Handler');
61
        $domainMapperMock = $this->getDomainMapperMock();
62
        $relationProcessorMock = $this->getRelationProcessorMock();
63
        $nameSchemaServiceMock = $this->getNameSchemaServiceMock();
64
        $fieldTypeRegistryMock = $this->getFieldTypeRegistryMock();
65
        $settings = ['default_version_archive_limit' => 10];
66
67
        $service = new ContentService(
68
            $repositoryMock,
0 ignored issues
show
Bug introduced by
It seems like $repositoryMock defined by $this->getRepositoryMock() on line 58 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...
69
            $persistenceHandlerMock,
70
            $domainMapperMock,
0 ignored issues
show
Bug introduced by
It seems like $domainMapperMock defined by $this->getDomainMapperMock() on line 61 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...
71
            $relationProcessorMock,
0 ignored issues
show
Bug introduced by
It seems like $relationProcessorMock defined by $this->getRelationProcessorMock() on line 62 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...
72
            $nameSchemaServiceMock,
0 ignored issues
show
Bug introduced by
It seems like $nameSchemaServiceMock defined by $this->getNameSchemaServiceMock() on line 63 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...
73
            $fieldTypeRegistryMock,
0 ignored issues
show
Bug introduced by
It seems like $fieldTypeRegistryMock defined by $this->getFieldTypeRegistryMock() on line 64 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...
74
            $settings
75
        );
76
77
        $this->assertAttributeSame(
78
            $repositoryMock,
79
            'repository',
80
            $service
81
        );
82
83
        $this->assertAttributeSame(
84
            $persistenceHandlerMock,
85
            'persistenceHandler',
86
            $service
87
        );
88
89
        $this->assertAttributeSame(
90
            $domainMapperMock,
91
            'domainMapper',
92
            $service
93
        );
94
95
        $this->assertAttributeSame(
96
            $relationProcessorMock,
97
            'relationProcessor',
98
            $service
99
        );
100
101
        $this->assertAttributeSame(
102
            $nameSchemaServiceMock,
103
            'nameSchemaService',
104
            $service
105
        );
106
107
        $this->assertAttributeSame(
108
            $fieldTypeRegistryMock,
109
            'fieldTypeRegistry',
110
            $service
111
        );
112
113
        $this->assertAttributeSame(
114
            $settings,
115
            'settings',
116
            $service
117
        );
118
    }
119
120
    /**
121
     * Test for the loadVersionInfo() method.
122
     *
123
     * @covers \eZ\Publish\Core\Repository\ContentService::loadVersionInfoById
124
     */
125
    public function testLoadVersionInfoById()
126
    {
127
        $repository = $this->getRepositoryMock();
128
        $contentServiceMock = $this->getPartlyMockedContentService(array('loadContentInfo'));
129
        /** @var \PHPUnit_Framework_MockObject_MockObject $contentHandler */
130
        $contentHandler = $this->getPersistenceMock()->contentHandler();
131
        $domainMapperMock = $this->getDomainMapperMock();
132
        $versionInfoMock = $this->getMock('eZ\\Publish\\API\\Repository\\Values\\Content\\VersionInfo');
133
134
        $versionInfoMock->expects($this->once())
135
            ->method('isPublished')
136
            ->willReturn(true);
137
138
        $contentServiceMock->expects($this->once())
139
            ->method('loadContentInfo')
140
            ->with($this->equalTo(42))
141
            ->will(
142
                $this->returnValue(
143
                    new ContentInfo(array('currentVersionNo' => 24))
144
                )
145
            );
146
147
        $contentHandler->expects($this->once())
148
            ->method('loadVersionInfo')
149
            ->with(
150
                $this->equalTo(42),
151
                $this->equalTo(24)
152
            )->will(
153
                $this->returnValue(new SPIVersionInfo())
154
            );
155
156
        $domainMapperMock->expects($this->once())
157
            ->method('buildVersionInfoDomainObject')
158
            ->with(new SPIVersionInfo())
159
            ->will($this->returnValue($versionInfoMock));
160
161
        $repository->expects($this->once())
162
            ->method('canUser')
163
            ->with(
164
                $this->equalTo('content'),
165
                $this->equalTo('read'),
166
                $this->equalTo($versionInfoMock)
167
            )->will($this->returnValue(true));
168
169
        $result = $contentServiceMock->loadVersionInfoById(42);
170
171
        $this->assertEquals($versionInfoMock, $result);
172
    }
173
174
    /**
175
     * Test for the loadVersionInfo() method.
176
     *
177
     * @covers \eZ\Publish\Core\Repository\ContentService::loadVersionInfoById
178
     * @expectedException \eZ\Publish\Core\Base\Exceptions\NotFoundException
179
     */
180
    public function testLoadVersionInfoByIdThrowsNotFoundException()
181
    {
182
        $contentServiceMock = $this->getPartlyMockedContentService(array('loadContentInfo'));
183
        /** @var \PHPUnit_Framework_MockObject_MockObject $contentHandler */
184
        $contentHandler = $this->getPersistenceMock()->contentHandler();
185
186
        $contentHandler->expects($this->once())
187
            ->method('loadVersionInfo')
188
            ->with(
189
                $this->equalTo(42),
190
                $this->equalTo(24)
191
            )->will(
192
                $this->throwException(
193
                    new NotFoundException(
194
                        'Content',
195
                        array(
196
                            'contentId' => 42,
197
                            'versionNo' => 24,
198
                        )
199
                    )
200
                )
201
            );
202
203
        $contentServiceMock->loadVersionInfoById(42, 24);
204
    }
205
206
    /**
207
     * Test for the loadVersionInfo() method.
208
     *
209
     * @covers \eZ\Publish\Core\Repository\ContentService::loadVersionInfoById
210
     * @expectedException \eZ\Publish\Core\Base\Exceptions\UnauthorizedException
211
     */
212
    public function testLoadVersionInfoByIdThrowsUnauthorizedExceptionNonPublishedVersion()
213
    {
214
        $repository = $this->getRepositoryMock();
215
        $contentServiceMock = $this->getPartlyMockedContentService();
216
        /** @var \PHPUnit_Framework_MockObject_MockObject $contentHandler */
217
        $contentHandler = $this->getPersistenceMock()->contentHandler();
218
        $domainMapperMock = $this->getDomainMapperMock();
219
        $versionInfoMock = $this->getMock('eZ\\Publish\\API\\Repository\\Values\\Content\\VersionInfo');
220
221
        $versionInfoMock->expects($this->any())
222
            ->method('isPublished')
223
            ->willReturn(false);
224
225
        $contentHandler->expects($this->once())
226
            ->method('loadVersionInfo')
227
            ->with(
228
                $this->equalTo(42),
229
                $this->equalTo(24)
230
            )->will(
231
                $this->returnValue(new SPIVersionInfo())
232
            );
233
234
        $domainMapperMock->expects($this->once())
235
            ->method('buildVersionInfoDomainObject')
236
            ->with(new SPIVersionInfo())
237
            ->will($this->returnValue($versionInfoMock));
238
239
        $repository->expects($this->once())
240
            ->method('canUser')
241
            ->with(
242
                $this->equalTo('content'),
243
                $this->equalTo('versionread'),
244
                $this->equalTo($versionInfoMock)
245
            )->will($this->returnValue(false));
246
247
        $contentServiceMock->loadVersionInfoById(42, 24);
248
    }
249
250
    /**
251
     * Test for the loadVersionInfo() method.
252
     *
253
     * @covers \eZ\Publish\Core\Repository\ContentService::loadVersionInfoById
254
     */
255 View Code Duplication
    public function testLoadVersionInfoByIdPublishedVersion()
256
    {
257
        $repository = $this->getRepositoryMock();
258
        $contentServiceMock = $this->getPartlyMockedContentService();
259
        /** @var \PHPUnit_Framework_MockObject_MockObject $contentHandler */
260
        $contentHandler = $this->getPersistenceMock()->contentHandler();
261
        $domainMapperMock = $this->getDomainMapperMock();
262
        $versionInfoMock = $this->getMock('eZ\\Publish\\API\\Repository\\Values\\Content\\VersionInfo');
263
264
        $versionInfoMock->expects($this->once())
265
            ->method('isPublished')
266
            ->willReturn(true);
267
268
        $contentHandler->expects($this->once())
269
            ->method('loadVersionInfo')
270
            ->with(
271
                $this->equalTo(42),
272
                $this->equalTo(24)
273
            )->will(
274
                $this->returnValue(new SPIVersionInfo())
275
            );
276
277
        $domainMapperMock->expects($this->once())
278
            ->method('buildVersionInfoDomainObject')
279
            ->with(new SPIVersionInfo())
280
            ->will($this->returnValue($versionInfoMock));
281
282
        $repository->expects($this->once())
283
            ->method('canUser')
284
            ->with(
285
                $this->equalTo('content'),
286
                $this->equalTo('read'),
287
                $this->equalTo($versionInfoMock)
288
            )->will($this->returnValue(true));
289
290
        $result = $contentServiceMock->loadVersionInfoById(42, 24);
291
292
        $this->assertEquals($versionInfoMock, $result);
293
    }
294
295
    /**
296
     * Test for the loadVersionInfo() method.
297
     *
298
     * @covers \eZ\Publish\Core\Repository\ContentService::loadVersionInfoById
299
     */
300 View Code Duplication
    public function testLoadVersionInfoByIdNonPublishedVersion()
301
    {
302
        $repository = $this->getRepositoryMock();
303
        $contentServiceMock = $this->getPartlyMockedContentService();
304
        /** @var \PHPUnit_Framework_MockObject_MockObject $contentHandler */
305
        $contentHandler = $this->getPersistenceMock()->contentHandler();
306
        $domainMapperMock = $this->getDomainMapperMock();
307
        $versionInfoMock = $this->getMock('eZ\\Publish\\API\\Repository\\Values\\Content\\VersionInfo');
308
309
        $versionInfoMock->expects($this->once())
310
            ->method('isPublished')
311
            ->willReturn(false);
312
313
        $contentHandler->expects($this->once())
314
            ->method('loadVersionInfo')
315
            ->with(
316
                $this->equalTo(42),
317
                $this->equalTo(24)
318
            )->will(
319
                $this->returnValue(new SPIVersionInfo())
320
            );
321
322
        $domainMapperMock->expects($this->once())
323
            ->method('buildVersionInfoDomainObject')
324
            ->with(new SPIVersionInfo())
325
            ->will($this->returnValue($versionInfoMock));
326
327
        $repository->expects($this->once())
328
            ->method('canUser')
329
            ->with(
330
                $this->equalTo('content'),
331
                $this->equalTo('versionread'),
332
                $this->equalTo($versionInfoMock)
333
            )->will($this->returnValue(true));
334
335
        $result = $contentServiceMock->loadVersionInfoById(42, 24);
336
337
        $this->assertEquals($versionInfoMock, $result);
338
    }
339
340
    /**
341
     * Test for the loadVersionInfo() method.
342
     *
343
     * @covers \eZ\Publish\Core\Repository\ContentService::loadVersionInfo
344
     * @depends eZ\Publish\Core\Repository\Tests\Service\Mock\ContentTest::testLoadVersionInfoById
345
     * @depends eZ\Publish\Core\Repository\Tests\Service\Mock\ContentTest::testLoadVersionInfoByIdThrowsNotFoundException
346
     * @depends eZ\Publish\Core\Repository\Tests\Service\Mock\ContentTest::testLoadVersionInfoByIdThrowsUnauthorizedExceptionNonPublishedVersion
347
     * @depends eZ\Publish\Core\Repository\Tests\Service\Mock\ContentTest::testLoadVersionInfoByIdPublishedVersion
348
     * @depends eZ\Publish\Core\Repository\Tests\Service\Mock\ContentTest::testLoadVersionInfoByIdNonPublishedVersion
349
     */
350
    public function testLoadVersionInfo()
351
    {
352
        $contentServiceMock = $this->getPartlyMockedContentService(
353
            array('loadVersionInfoById')
354
        );
355
        $contentServiceMock->expects(
356
            $this->once()
357
        )->method(
358
            'loadVersionInfoById'
359
        )->with(
360
            $this->equalTo(42),
361
            $this->equalTo(7)
362
        )->will(
363
            $this->returnValue('result')
364
        );
365
366
        $result = $contentServiceMock->loadVersionInfo(
367
            new ContentInfo(array('id' => 42)),
368
            7
369
        );
370
371
        $this->assertEquals('result', $result);
372
    }
373
374
    public function testLoadContent()
375
    {
376
        $repository = $this->getRepositoryMock();
377
        $contentService = $this->getPartlyMockedContentService(array('internalLoadContent'));
378
        $content = $this->getMock('eZ\Publish\API\Repository\Values\Content\Content');
379
        $versionInfo = $this->getMock('eZ\\Publish\\API\\Repository\\Values\\Content\\VersionInfo');
380
        $content
381
            ->expects($this->once())
382
            ->method('getVersionInfo')
383
            ->will($this->returnValue($versionInfo));
384
        $versionInfo
385
            ->expects($this->once())
386
            ->method('isPublished')
387
            ->willReturn(true);
388
        $contentId = 123;
389
        $contentService
390
            ->expects($this->once())
391
            ->method('internalLoadContent')
392
            ->with($contentId)
393
            ->will($this->returnValue($content));
394
395
        $repository
396
            ->expects($this->once())
397
            ->method('canUser')
398
            ->with('content', 'read', $content)
399
            ->will($this->returnValue(true));
400
401
        $this->assertSame($content, $contentService->loadContent($contentId));
402
    }
403
404 View Code Duplication
    public function testLoadContentNonPublished()
405
    {
406
        $repository = $this->getRepositoryMock();
407
        $contentService = $this->getPartlyMockedContentService(array('internalLoadContent'));
408
        $content = $this->getMock('eZ\Publish\API\Repository\Values\Content\Content');
409
        $versionInfo = $this
410
            ->getMockBuilder('eZ\Publish\API\Repository\Values\Content\VersionInfo')
411
            ->getMockForAbstractClass();
412
        $content
413
            ->expects($this->once())
414
            ->method('getVersionInfo')
415
            ->will($this->returnValue($versionInfo));
416
        $contentId = 123;
417
        $contentService
418
            ->expects($this->once())
419
            ->method('internalLoadContent')
420
            ->with($contentId)
421
            ->will($this->returnValue($content));
422
423
        $repository
424
            ->expects($this->exactly(2))
425
            ->method('canUser')
426
            ->will(
427
                $this->returnValueMap(
428
                    array(
429
                        array('content', 'read', $content, null, true),
430
                        array('content', 'versionread', $content, null, true),
431
                    )
432
                )
433
            );
434
435
        $this->assertSame($content, $contentService->loadContent($contentId));
436
    }
437
438
    /**
439
     * @expectedException \eZ\Publish\Core\Base\Exceptions\UnauthorizedException
440
     */
441
    public function testLoadContentUnauthorized()
442
    {
443
        $repository = $this->getRepositoryMock();
444
        $contentService = $this->getPartlyMockedContentService(array('internalLoadContent'));
445
        $content = $this->getMock('eZ\Publish\API\Repository\Values\Content\Content');
446
        $contentId = 123;
447
        $contentService
448
            ->expects($this->once())
449
            ->method('internalLoadContent')
450
            ->with($contentId)
451
            ->will($this->returnValue($content));
452
453
        $repository
454
            ->expects($this->once())
455
            ->method('canUser')
456
            ->with('content', 'read', $content)
457
            ->will($this->returnValue(false));
458
459
        $contentService->loadContent($contentId);
460
    }
461
462
    /**
463
     * @expectedException \eZ\Publish\Core\Base\Exceptions\UnauthorizedException
464
     */
465 View Code Duplication
    public function testLoadContentNotPublishedStatusUnauthorized()
466
    {
467
        $repository = $this->getRepositoryMock();
468
        $contentService = $this->getPartlyMockedContentService(array('internalLoadContent'));
469
        $content = $this->getMock('eZ\Publish\API\Repository\Values\Content\Content');
470
        $versionInfo = $this
471
            ->getMockBuilder('eZ\Publish\API\Repository\Values\Content\VersionInfo')
472
            ->getMockForAbstractClass();
473
        $content
474
            ->expects($this->once())
475
            ->method('getVersionInfo')
476
            ->will($this->returnValue($versionInfo));
477
        $contentId = 123;
478
        $contentService
479
            ->expects($this->once())
480
            ->method('internalLoadContent')
481
            ->with($contentId)
482
            ->will($this->returnValue($content));
483
484
        $repository
485
            ->expects($this->exactly(2))
486
            ->method('canUser')
487
            ->will(
488
                $this->returnValueMap(
489
                    array(
490
                        array('content', 'read', $content, null, true),
491
                        array('content', 'versionread', $content, null, false),
492
                    )
493
                )
494
            );
495
496
        $contentService->loadContent($contentId);
497
    }
498
499
    /**
500
     * @dataProvider internalLoadContentProvider
501
     */
502
    public function testInternalLoadContent($id, $languages, $versionNo, $isRemoteId, $useAlwaysAvailable)
503
    {
504
        $contentService = $this->getPartlyMockedContentService();
505
        /** @var \PHPUnit_Framework_MockObject_MockObject $contentHandler */
506
        $contentHandler = $this->getPersistenceMock()->contentHandler();
507
        $realVersionNo = $versionNo;
508
        $realId = $id;
509
510
        if ($isRemoteId) {
511
            $realVersionNo = $versionNo ?: 7;
512
            $realId = 123;
513
            $spiContentInfo = new SPIContentInfo(array('currentVersionNo' => $realVersionNo, 'id' => $realId));
514
            $contentHandler
515
                ->expects($this->once())
516
                ->method('loadContentInfoByRemoteId')
517
                ->with($id)
518
                ->will($this->returnValue($spiContentInfo));
519
        } elseif ($versionNo === null) {
520
            $realVersionNo = 7;
521
            $spiContentInfo = new SPIContentInfo(array('currentVersionNo' => $realVersionNo));
522
            $contentHandler
523
                ->expects($this->once())
524
                ->method('loadContentInfo')
525
                ->with($id)
526
                ->will($this->returnValue($spiContentInfo));
527
        } elseif (!empty($languages) && $useAlwaysAvailable) {
528
            $spiContentInfo = new SPIContentInfo(array('alwaysAvailable' => false));
529
            $contentHandler
530
                ->expects($this->once())
531
                ->method('loadContentInfo')
532
                ->with($id)
533
                ->will($this->returnValue($spiContentInfo));
534
        }
535
536
        $spiContent = new SPIContent();
537
        $contentHandler
538
            ->expects($this->once())
539
            ->method('load')
540
            ->with($realId, $realVersionNo, $languages)
541
            ->will($this->returnValue($spiContent));
542
        $content = $this->getMock('eZ\Publish\API\Repository\Values\Content\Content');
543
        $this->getDomainMapperMock()
544
            ->expects($this->once())
545
            ->method('buildContentDomainObject')
546
            ->with($spiContent)
547
            ->will($this->returnValue($content));
548
549
        $this->assertSame(
550
            $content,
551
            $contentService->internalLoadContent($id, $languages, $versionNo, $isRemoteId, $useAlwaysAvailable)
552
        );
553
    }
554
555
    public function internalLoadContentProvider()
556
    {
557
        return array(
558
            array(123, null, null, false, false),
559
            array(123, null, 456, false, false),
560
            array(456, null, 123, false, true),
561
            array(456, null, 2, false, false),
562
            array(456, array('eng-GB'), 2, false, true),
563
            array(456, array('eng-GB', 'fre-FR'), null, false, false),
564
            array(456, array('eng-GB', 'fre-FR', 'nor-NO'), 2, false, false),
565
            // With remoteId
566
            array(123, null, null, true, false),
567
            array('someRemoteId', null, 456, true, false),
568
            array(456, null, 123, true, false),
569
            array('someRemoteId', null, 2, true, false),
570
            array('someRemoteId', array('eng-GB'), 2, true, false),
571
            array(456, array('eng-GB', 'fre-FR'), null, true, false),
572
            array('someRemoteId', array('eng-GB', 'fre-FR', 'nor-NO'), 2, true, false),
573
        );
574
    }
575
576
    /**
577
     * @expectedException \eZ\Publish\Core\Base\Exceptions\NotFoundException
578
     */
579
    public function testInternalLoadContentNotFound()
580
    {
581
        $contentService = $this->getPartlyMockedContentService();
582
        /** @var \PHPUnit_Framework_MockObject_MockObject $contentHandler */
583
        $contentHandler = $this->getPersistenceMock()->contentHandler();
584
        $id = 123;
585
        $versionNo = 7;
586
        $languages = null;
587
        $contentHandler
588
            ->expects($this->once())
589
            ->method('load')
590
            ->with($id, $versionNo, $languages)
591
            ->will(
592
                $this->throwException(
593
                    $this->getMock('eZ\Publish\API\Repository\Exceptions\NotFoundException')
594
                )
595
            );
596
597
        $contentService->internalLoadContent($id, $languages, $versionNo);
598
    }
599
600
    /**
601
     * Test for the loadContentByContentInfo() method.
602
     *
603
     * @covers \eZ\Publish\Core\Repository\ContentService::loadContentByContentInfo
604
     */
605
    public function testLoadContentByContentInfo()
606
    {
607
        $contentServiceMock = $this->getPartlyMockedContentService(
608
            array('loadContent')
609
        );
610
        $contentServiceMock->expects(
611
            $this->once()
612
        )->method(
613
            'loadContent'
614
        )->with(
615
            $this->equalTo(42),
616
            $this->equalTo(array('cro-HR')),
617
            $this->equalTo(7),
618
            $this->equalTo(false)
619
        )->will(
620
            $this->returnValue('result')
621
        );
622
623
        $result = $contentServiceMock->loadContentByContentInfo(
624
            new ContentInfo(array('id' => 42)),
625
            array('cro-HR'),
626
            7
627
        );
628
629
        $this->assertEquals('result', $result);
630
    }
631
632
    /**
633
     * Test for the loadContentByVersionInfo() method.
634
     *
635
     * @covers \eZ\Publish\Core\Repository\ContentService::loadContentByVersionInfo
636
     */
637
    public function testLoadContentByVersionInfo()
638
    {
639
        $contentServiceMock = $this->getPartlyMockedContentService(
640
            array('loadContent')
641
        );
642
        $contentServiceMock->expects(
643
            $this->once()
644
        )->method(
645
            'loadContent'
646
        )->with(
647
            $this->equalTo(42),
648
            $this->equalTo(array('cro-HR')),
649
            $this->equalTo(7),
650
            $this->equalTo(false)
651
        )->will(
652
            $this->returnValue('result')
653
        );
654
655
        $result = $contentServiceMock->loadContentByVersionInfo(
656
            new VersionInfo(
657
                array(
658
                    'contentInfo' => new ContentInfo(array('id' => 42)),
659
                    'versionNo' => 7,
660
                )
661
            ),
662
            array('cro-HR')
663
        );
664
665
        $this->assertEquals('result', $result);
666
    }
667
668
    /**
669
     * Test for the deleteContent() method.
670
     *
671
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteContent
672
     * @expectedException \eZ\Publish\Core\Base\Exceptions\UnauthorizedException
673
     */
674
    public function testDeleteContentThrowsUnauthorizedException()
675
    {
676
        $repository = $this->getRepositoryMock();
677
        $contentService = $this->getPartlyMockedContentService(array('internalLoadContentInfo'));
678
        $contentInfo = $this->getMock('eZ\\Publish\\API\\Repository\\Values\\Content\\ContentInfo');
679
680
        $contentInfo->expects($this->any())
681
            ->method('__get')
682
            ->with('id')
683
            ->will($this->returnValue(42));
684
685
        $contentService->expects($this->once())
686
            ->method('internalLoadContentInfo')
687
            ->with(42)
688
            ->will($this->returnValue($contentInfo));
689
690
        $repository->expects($this->once())
691
            ->method('canUser')
692
            ->with('content', 'remove')
693
            ->will($this->returnValue(false));
694
695
        /* @var \eZ\Publish\API\Repository\Values\Content\ContentInfo $contentInfo */
696
        $contentService->deleteContent($contentInfo);
697
    }
698
699
    /**
700
     * Test for the deleteContent() method.
701
     *
702
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteContent
703
     */
704
    public function testDeleteContent()
705
    {
706
        $repository = $this->getRepositoryMock();
707
708
        $repository->expects($this->once())
709
            ->method('canUser')
710
            ->with('content', 'remove')
711
            ->will($this->returnValue(true));
712
713
        $contentService = $this->getPartlyMockedContentService(array('internalLoadContentInfo'));
714
        /** @var \PHPUnit_Framework_MockObject_MockObject $urlAliasHandler */
715
        $urlAliasHandler = $this->getPersistenceMock()->urlAliasHandler();
716
        /** @var \PHPUnit_Framework_MockObject_MockObject $locationHandler */
717
        $locationHandler = $this->getPersistenceMock()->locationHandler();
718
        /** @var \PHPUnit_Framework_MockObject_MockObject $contentHandler */
719
        $contentHandler = $this->getPersistenceMock()->contentHandler();
720
721
        $contentInfo = $this->getMock('eZ\\Publish\\API\\Repository\\Values\\Content\\ContentInfo');
722
723
        $contentService->expects($this->once())
724
            ->method('internalLoadContentInfo')
725
            ->with(42)
726
            ->will($this->returnValue($contentInfo));
727
728
        $contentInfo->expects($this->any())
729
            ->method('__get')
730
            ->with('id')
731
            ->will($this->returnValue(42));
732
733
        $repository->expects($this->once())->method('beginTransaction');
734
735
        $spiLocations = array(
736
            new SPILocation(array('id' => 1)),
737
            new SPILocation(array('id' => 2)),
738
        );
739
        $locationHandler->expects($this->once())
740
            ->method('loadLocationsByContent')
741
            ->with(42)
742
            ->will($this->returnValue($spiLocations));
743
744
        $contentHandler->expects($this->once())
745
            ->method('deleteContent')
746
            ->with(42);
747
748
        foreach ($spiLocations as $index => $spiLocation) {
749
            $urlAliasHandler->expects($this->at($index))
750
                ->method('locationDeleted')
751
                ->with($spiLocation->id);
752
        }
753
754
        $repository->expects($this->once())->method('commit');
755
756
        /* @var \eZ\Publish\API\Repository\Values\Content\ContentInfo $contentInfo */
757
        $contentService->deleteContent($contentInfo);
758
    }
759
760
    /**
761
     * Test for the deleteContent() method.
762
     *
763
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteContent
764
     * @expectedException \Exception
765
     */
766
    public function testDeleteContentWithRollback()
767
    {
768
        $repository = $this->getRepositoryMock();
769
770
        $repository->expects($this->once())
771
            ->method('canUser')
772
            ->with('content', 'remove')
773
            ->will($this->returnValue(true));
774
775
        $contentService = $this->getPartlyMockedContentService(array('internalLoadContentInfo'));
776
        /** @var \PHPUnit_Framework_MockObject_MockObject $locationHandler */
777
        $locationHandler = $this->getPersistenceMock()->locationHandler();
778
779
        $contentInfo = $this->getMock('eZ\\Publish\\API\\Repository\\Values\\Content\\ContentInfo');
780
781
        $contentService->expects($this->once())
782
            ->method('internalLoadContentInfo')
783
            ->with(42)
784
            ->will($this->returnValue($contentInfo));
785
786
        $contentInfo->expects($this->any())
787
            ->method('__get')
788
            ->with('id')
789
            ->will($this->returnValue(42));
790
791
        $repository->expects($this->once())->method('beginTransaction');
792
793
        $locationHandler->expects($this->once())
794
            ->method('loadLocationsByContent')
795
            ->with(42)
796
            ->will($this->throwException(new \Exception()));
797
798
        $repository->expects($this->once())->method('rollback');
799
800
        /* @var \eZ\Publish\API\Repository\Values\Content\ContentInfo $contentInfo */
801
        $contentService->deleteContent($contentInfo);
802
    }
803
804
    /**
805
     * Test for the deleteVersion() method.
806
     *
807
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteVersion
808
     * @expectedException \eZ\Publish\API\Repository\Exceptions\BadStateException
809
     */
810
    public function testDeleteVersionThrowsBadStateExceptionLastVersion()
811
    {
812
        $repository = $this->getRepositoryMock();
813
        $repository
814
            ->expects($this->once())
815
            ->method('canUser')
816
            ->with('content', 'versionremove')
817
            ->will($this->returnValue(true));
818
        $repository
819
            ->expects($this->never())
820
            ->method('beginTransaction');
821
822
        $contentService = $this->getPartlyMockedContentService();
823
        /** @var \PHPUnit_Framework_MockObject_MockObject $contentHandler */
824
        $contentHandler = $this->getPersistenceMock()->contentHandler();
825
        $contentInfo = $this->getMock('eZ\\Publish\\API\\Repository\\Values\\Content\\ContentInfo');
826
        $versionInfo = $this->getMock('eZ\\Publish\\API\\Repository\\Values\\Content\\VersionInfo');
827
828
        $contentInfo
829
            ->expects($this->any())
830
            ->method('__get')
831
            ->with('id')
832
            ->will($this->returnValue(42));
833
834
        $versionInfo
835
            ->expects($this->any())
836
            ->method('__get')
837
            ->will(
838
                $this->returnValueMap(
839
                    array(
840
                        array('versionNo', 123),
841
                        array('contentInfo', $contentInfo),
842
                    )
843
                )
844
            );
845
        $versionInfo
846
            ->expects($this->once())
847
            ->method('isPublished')
848
            ->willReturn(false);
849
850
        $contentHandler
851
            ->expects($this->once())
852
            ->method('listVersions')
853
            ->with(42)
854
            ->will($this->returnValue(array('version')));
855
856
        /* @var \eZ\Publish\API\Repository\Values\Content\VersionInfo $versionInfo */
857
        $contentService->deleteVersion($versionInfo);
858
    }
859
860
    /**
861
     * Test for the createContent() method.
862
     *
863
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
864
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
865
     * @expectedExceptionMessage Argument '$contentCreateStruct' is invalid: 'mainLanguageCode' property must be set
866
     */
867
    public function testCreateContentThrowsInvalidArgumentExceptionMainLanguageCodeNotSet()
868
    {
869
        $mockedService = $this->getPartlyMockedContentService();
870
        $mockedService->createContent(new ContentCreateStruct(), array());
871
    }
872
873
    /**
874
     * Test for the createContent() method.
875
     *
876
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
877
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
878
     * @expectedExceptionMessage Argument '$contentCreateStruct' is invalid: 'contentType' property must be set
879
     */
880
    public function testCreateContentThrowsInvalidArgumentExceptionContentTypeNotSet()
881
    {
882
        $mockedService = $this->getPartlyMockedContentService();
883
        $mockedService->createContent(
884
            new ContentCreateStruct(array('mainLanguageCode' => 'eng-US')),
885
            array()
886
        );
887
    }
888
889
    /**
890
     * Test for the createContent() method.
891
     *
892
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
893
     * @expectedException \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
894
     */
895
    public function testCreateContentThrowsUnauthorizedException()
896
    {
897
        $repositoryMock = $this->getRepositoryMock();
898
        $mockedService = $this->getPartlyMockedContentService();
899
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
900
        $contentType = new ContentType(
901
            array(
902
                'id' => 123,
903
                'fieldDefinitions' => array(),
904
            )
905
        );
906
        $contentCreateStruct = new ContentCreateStruct(
907
            array(
908
                'ownerId' => 169,
909
                'alwaysAvailable' => false,
910
                'mainLanguageCode' => 'eng-US',
911
                'contentType' => $contentType,
912
            )
913
        );
914
915
        $repositoryMock->expects($this->once())
916
            ->method('getCurrentUserReference')
917
            ->will($this->returnValue(new UserReference(169)));
918
919
        $contentTypeServiceMock->expects($this->once())
920
            ->method('loadContentType')
921
            ->with($this->equalTo(123))
922
            ->will($this->returnValue($contentType));
923
924
        $repositoryMock->expects($this->once())
925
            ->method('getContentTypeService')
926
            ->will($this->returnValue($contentTypeServiceMock));
927
928
        $repositoryMock->expects($this->once())
929
            ->method('canUser')
930
            ->with(
931
                $this->equalTo('content'),
932
                $this->equalTo('create'),
933
                $this->isInstanceOf($contentCreateStruct),
0 ignored issues
show
Documentation introduced by
$contentCreateStruct is of type object<eZ\Publish\Core\R...nt\ContentCreateStruct>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
934
                $this->equalTo(array())
935
            )->will($this->returnValue(false));
936
937
        $mockedService->createContent(
938
            new ContentCreateStruct(
939
                array(
940
                    'mainLanguageCode' => 'eng-US',
941
                    'contentType' => $contentType,
942
                )
943
            ),
944
            array()
945
        );
946
    }
947
948
    /**
949
     * Test for the createContent() method.
950
     *
951
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
952
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
953
     * @exceptionMessage Argument '$contentCreateStruct' is invalid: Another content with remoteId 'faraday' exists
954
     */
955
    public function testCreateContentThrowsInvalidArgumentExceptionDuplicateRemoteId()
956
    {
957
        $repositoryMock = $this->getRepositoryMock();
958
        $mockedService = $this->getPartlyMockedContentService(array('loadContentByRemoteId'));
959
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
960
        $contentType = new ContentType(
961
            array(
962
                'id' => 123,
963
                'fieldDefinitions' => array(),
964
            )
965
        );
966
        $contentCreateStruct = new ContentCreateStruct(
967
            array(
968
                'ownerId' => 169,
969
                'alwaysAvailable' => false,
970
                'remoteId' => 'faraday',
971
                'mainLanguageCode' => 'eng-US',
972
                'contentType' => $contentType,
973
            )
974
        );
975
976
        $repositoryMock->expects($this->once())
977
            ->method('getCurrentUserReference')
978
            ->will($this->returnValue(new UserReference(169)));
979
980
        $contentTypeServiceMock->expects($this->once())
981
            ->method('loadContentType')
982
            ->with($this->equalTo(123))
983
            ->will($this->returnValue($contentType));
984
985
        $repositoryMock->expects($this->once())
986
            ->method('getContentTypeService')
987
            ->will($this->returnValue($contentTypeServiceMock));
988
989
        $repositoryMock->expects($this->once())
990
            ->method('canUser')
991
            ->with(
992
                $this->equalTo('content'),
993
                $this->equalTo('create'),
994
                $this->isInstanceOf($contentCreateStruct),
0 ignored issues
show
Documentation introduced by
$contentCreateStruct is of type object<eZ\Publish\Core\R...nt\ContentCreateStruct>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
995
                $this->equalTo(array())
996
            )->will($this->returnValue(true));
997
998
        $mockedService->expects($this->once())
999
            ->method('loadContentByRemoteId')
1000
            ->with($contentCreateStruct->remoteId)
1001
            ->will($this->returnValue('Hello...'));
1002
1003
        $mockedService->createContent(
1004
            new ContentCreateStruct(
1005
                array(
1006
                    'remoteId' => 'faraday',
1007
                    'mainLanguageCode' => 'eng-US',
1008
                    'contentType' => $contentType,
1009
                )
1010
            ),
1011
            array()
1012
        );
1013
    }
1014
1015
    /**
1016
     * @param string $mainLanguageCode
1017
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $structFields
1018
     * @param \eZ\Publish\API\Repository\Values\ContentType\FieldDefinition[] $fieldDefinitions
1019
     *
1020
     * @return array
1021
     */
1022
    protected function mapStructFieldsForCreate($mainLanguageCode, $structFields, $fieldDefinitions)
1023
    {
1024
        $mappedFieldDefinitions = array();
1025
        foreach ($fieldDefinitions as $fieldDefinition) {
1026
            $mappedFieldDefinitions[$fieldDefinition->identifier] = $fieldDefinition;
1027
        }
1028
1029
        $mappedStructFields = array();
1030
        foreach ($structFields as $structField) {
1031
            if ($structField->languageCode === null) {
1032
                $languageCode = $mainLanguageCode;
1033
            } else {
1034
                $languageCode = $structField->languageCode;
1035
            }
1036
1037
            $mappedStructFields[$structField->fieldDefIdentifier][$languageCode] = (string)$structField->value;
0 ignored issues
show
Documentation introduced by
The property $value is declared protected in eZ\Publish\API\Repository\Values\Content\Field. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
1038
        }
1039
1040
        return $mappedStructFields;
1041
    }
1042
1043
    /**
1044
     * Returns full, possibly redundant array of field values, indexed by field definition
1045
     * identifier and language code.
1046
     *
1047
     * @throws \RuntimeException Method is intended to be used only with consistent fixtures
1048
     *
1049
     * @param string $mainLanguageCode
1050
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $structFields
1051
     * @param \eZ\Publish\API\Repository\Values\ContentType\FieldDefinition[] $fieldDefinitions
1052
     * @param array $languageCodes
1053
     *
1054
     * @return array
1055
     */
1056
    protected function determineValuesForCreate(
1057
        $mainLanguageCode,
1058
        array $structFields,
1059
        array $fieldDefinitions,
1060
        array $languageCodes
1061
    ) {
1062
        $mappedStructFields = $this->mapStructFieldsForCreate(
1063
            $mainLanguageCode,
1064
            $structFields,
1065
            $fieldDefinitions
1066
        );
1067
1068
        $values = array();
1069
1070
        foreach ($fieldDefinitions as $fieldDefinition) {
1071
            $identifier = $fieldDefinition->identifier;
1072
            foreach ($languageCodes as $languageCode) {
1073 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...
1074
                    if (isset($mappedStructFields[$identifier][$mainLanguageCode])) {
1075
                        $values[$identifier][$languageCode] = $mappedStructFields[$identifier][$mainLanguageCode];
1076
                    } else {
1077
                        $values[$identifier][$languageCode] = (string)$fieldDefinition->defaultValue;
0 ignored issues
show
Documentation introduced by
The property $defaultValue is declared protected in eZ\Publish\API\Repositor...entType\FieldDefinition. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
1078
                    }
1079
                    continue;
1080
                }
1081
1082 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...
1083
                    $values[$identifier][$languageCode] = $mappedStructFields[$identifier][$languageCode];
1084
                    continue;
1085
                }
1086
1087
                $values[$identifier][$languageCode] = (string)$fieldDefinition->defaultValue;
0 ignored issues
show
Documentation introduced by
The property $defaultValue is declared protected in eZ\Publish\API\Repositor...entType\FieldDefinition. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
1088
            }
1089
        }
1090
1091
        return $this->stubValues($values);
1092
    }
1093
1094
    /**
1095
     * @param string $mainLanguageCode
1096
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $structFields
1097
     *
1098
     * @return string[]
1099
     */
1100
    protected function determineLanguageCodesForCreate($mainLanguageCode, array $structFields)
1101
    {
1102
        $languageCodes = array();
1103
1104 View Code Duplication
        foreach ($structFields as $field) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

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

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1898
                $this->equalTo(array())
1899
            )->will($this->returnValue(true));
1900
1901
        $mockedService->expects($this->once())
1902
            ->method('loadContentByRemoteId')
1903
            ->with($contentCreateStruct->remoteId)
1904
            ->will(
1905
                $this->throwException(new NotFoundException('Content', 'faraday'))
1906
            );
1907
1908
        $mockedService->createContent($contentCreateStruct, array());
1909
    }
1910
1911 View Code Duplication
    public function providerForTestCreateContentThrowsContentValidationExceptionFieldDefinition()
1912
    {
1913
        return array(
1914
            array(
1915
                'eng-GB',
1916
                array(
1917
                    new Field(
1918
                        array(
1919
                            'fieldDefIdentifier' => 'identifier',
1920
                            'value' => 'newValue',
1921
                            'languageCode' => 'eng-GB',
1922
                        )
1923
                    ),
1924
                ),
1925
            ),
1926
        );
1927
    }
1928
1929
    /**
1930
     * Test for the createContent() method.
1931
     *
1932
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
1933
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForCreate
1934
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
1935
     * @dataProvider providerForTestCreateContentThrowsContentValidationExceptionFieldDefinition
1936
     * @expectedException \eZ\Publish\API\Repository\Exceptions\ContentValidationException
1937
     * @expectedExceptionMessage Field definition 'identifier' does not exist in given ContentType
1938
     */
1939
    public function testCreateContentThrowsContentValidationExceptionFieldDefinition($mainLanguageCode, $structFields)
1940
    {
1941
        $this->assertForCreateContentContentValidationException(
1942
            $mainLanguageCode,
1943
            $structFields,
1944
            array()
1945
        );
1946
    }
1947
1948 View Code Duplication
    public function providerForTestCreateContentThrowsContentValidationExceptionTranslation()
1949
    {
1950
        return array(
1951
            array(
1952
                'eng-GB',
1953
                array(
1954
                    new Field(
1955
                        array(
1956
                            'fieldDefIdentifier' => 'identifier',
1957
                            'value' => 'newValue',
1958
                            'languageCode' => 'eng-US',
1959
                        )
1960
                    ),
1961
                ),
1962
            ),
1963
        );
1964
    }
1965
1966
    /**
1967
     * Test for the createContent() method.
1968
     *
1969
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
1970
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForCreate
1971
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
1972
     * @dataProvider providerForTestCreateContentThrowsContentValidationExceptionTranslation
1973
     * @expectedException \eZ\Publish\API\Repository\Exceptions\ContentValidationException
1974
     * @expectedExceptionMessage A value is set for non translatable field definition 'identifier' with language 'eng-US'
1975
     */
1976 View Code Duplication
    public function testCreateContentThrowsContentValidationExceptionTranslation($mainLanguageCode, $structFields)
1977
    {
1978
        $fieldDefinitions = array(
1979
            new FieldDefinition(
1980
                array(
1981
                    'id' => 'fieldDefinitionId1',
1982
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
1983
                    'isTranslatable' => false,
1984
                    'identifier' => 'identifier',
1985
                    'isRequired' => false,
1986
                    'defaultValue' => self::EMPTY_FIELD_VALUE,
1987
                )
1988
            ),
1989
        );
1990
1991
        $this->assertForCreateContentContentValidationException(
1992
            $mainLanguageCode,
1993
            $structFields,
1994
            $fieldDefinitions
1995
        );
1996
    }
1997
1998
    /**
1999
     * Asserts behaviour necessary for testing ContentFieldValidationException because of required
2000
     * field being empty.
2001
     *
2002
     * @param string $mainLanguageCode
2003
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $structFields
2004
     * @param \eZ\Publish\API\Repository\Values\ContentType\FieldDefinition[] $fieldDefinitions
2005
     *
2006
     * @return mixed
2007
     */
2008
    protected function assertForTestCreateContentRequiredField(
2009
        $mainLanguageCode,
2010
        array $structFields,
2011
        array $fieldDefinitions
2012
    ) {
2013
        $repositoryMock = $this->getRepositoryMock();
2014
        /** @var \PHPUnit_Framework_MockObject_MockObject $languageHandlerMock */
2015
        $languageHandlerMock = $this->getPersistenceMock()->contentLanguageHandler();
2016
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
2017
        $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...
2018
        $domainMapperMock = $this->getDomainMapperMock();
2019
        $fieldTypeMock = $this->getMock('eZ\\Publish\\SPI\\FieldType\\FieldType');
2020
        $contentType = new ContentType(
2021
            array(
2022
                'id' => 123,
2023
                'fieldDefinitions' => $fieldDefinitions,
2024
                'nameSchema' => '<nameSchema>',
2025
            )
2026
        );
2027
        $contentCreateStruct = new ContentCreateStruct(
2028
            array(
2029
                'fields' => $structFields,
2030
                'mainLanguageCode' => $mainLanguageCode,
2031
                'contentType' => $contentType,
2032
                'alwaysAvailable' => false,
2033
                'ownerId' => 169,
2034
                'sectionId' => 1,
2035
            )
2036
        );
2037
2038
        $languageHandlerMock->expects($this->any())
2039
            ->method('loadByLanguageCode')
2040
            ->with($this->isType('string'))
2041
            ->will(
2042
                $this->returnCallback(
2043
                    function () {
2044
                        return new Language(array('id' => 4242));
2045
                    }
2046
                )
2047
            );
2048
2049
        $contentTypeServiceMock->expects($this->once())
2050
            ->method('loadContentType')
2051
            ->with($this->equalTo($contentType->id))
2052
            ->will($this->returnValue($contentType));
2053
2054
        $repositoryMock->expects($this->once())
2055
            ->method('getContentTypeService')
2056
            ->will($this->returnValue($contentTypeServiceMock));
2057
2058
        $that = $this;
2059
        $repositoryMock->expects($this->once())
2060
            ->method('canUser')
2061
            ->with(
2062
                $this->equalTo('content'),
2063
                $this->equalTo('create'),
2064
                $this->isInstanceOf('eZ\\Publish\\API\\Repository\\Values\\Content\\ContentCreateStruct'),
2065
                $this->equalTo(array())
2066
            )->will(
2067
                $this->returnCallback(
2068
                    function () use ($that, $contentCreateStruct) {
2069
                        $that->assertEquals($contentCreateStruct, func_get_arg(2));
2070
2071
                        return true;
2072
                    }
2073
                )
2074
            );
2075
2076
        $domainMapperMock->expects($this->once())
2077
            ->method('getUniqueHash')
2078
            ->with($this->isInstanceOf('eZ\\Publish\\API\\Repository\\Values\\Content\\ContentCreateStruct'))
2079
            ->will(
2080
                $this->returnCallback(
2081
                    function ($object) use ($that, $contentCreateStruct) {
2082
                        $that->assertEquals($contentCreateStruct, $object);
2083
2084
                        return 'hash';
2085
                    }
2086
                )
2087
            );
2088
2089
        $fieldTypeMock->expects($this->any())
2090
            ->method('acceptValue')
2091
            ->will(
2092
                $this->returnCallback(
2093
                    function ($valueString) {
2094
                        return new ValueStub($valueString);
2095
                    }
2096
                )
2097
            );
2098
2099
        $emptyValue = self::EMPTY_FIELD_VALUE;
2100
        $fieldTypeMock->expects($this->any())
2101
            ->method('isEmptyValue')
2102
            ->will(
2103
                $this->returnCallback(
2104
                    function (ValueStub $value) use ($emptyValue) {
2105
                        return $emptyValue === (string)$value;
2106
                    }
2107
                )
2108
            );
2109
2110
        $fieldTypeMock->expects($this->any())
2111
            ->method('validate')
2112
            ->will($this->returnValue(array()));
2113
2114
        $this->getFieldTypeRegistryMock()->expects($this->any())
2115
            ->method('getFieldType')
2116
            ->will($this->returnValue($fieldTypeMock));
2117
2118
        return $contentCreateStruct;
2119
    }
2120
2121 View Code Duplication
    public function providerForTestCreateContentThrowsContentValidationExceptionRequiredField()
2122
    {
2123
        return array(
2124
            array(
2125
                'eng-US',
2126
                array(
2127
                    new Field(
2128
                        array(
2129
                            'fieldDefIdentifier' => 'identifier',
2130
                            'value' => self::EMPTY_FIELD_VALUE,
2131
                            'languageCode' => null,
2132
                        )
2133
                    ),
2134
                ),
2135
                'identifier',
2136
                'eng-US',
2137
            ),
2138
        );
2139
    }
2140
2141
    /**
2142
     * Test for the createContent() method.
2143
     *
2144
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
2145
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForCreate
2146
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
2147
     * @dataProvider providerForTestCreateContentThrowsContentValidationExceptionRequiredField
2148
     * @expectedException \eZ\Publish\API\Repository\Exceptions\ContentFieldValidationException
2149
     */
2150
    public function testCreateContentRequiredField(
2151
        $mainLanguageCode,
2152
        $structFields,
2153
        $identifier,
2154
        $languageCode
2155
    ) {
2156
        $fieldDefinitions = array(
2157
            new FieldDefinition(
2158
                array(
2159
                    'id' => 'fieldDefinitionId',
2160
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
2161
                    'isTranslatable' => true,
2162
                    'identifier' => 'identifier',
2163
                    'isRequired' => true,
2164
                    'defaultValue' => 'defaultValue',
2165
                )
2166
            ),
2167
        );
2168
        $contentCreateStruct = $this->assertForTestCreateContentRequiredField(
2169
            $mainLanguageCode,
2170
            $structFields,
2171
            $fieldDefinitions
2172
        );
2173
2174
        $mockedService = $this->getPartlyMockedContentService();
2175
2176
        try {
2177
            $mockedService->createContent($contentCreateStruct, array());
2178
        } catch (ContentValidationException $e) {
2179
            $this->assertEquals(
2180
                "Value for required field definition '{$identifier}' with language '{$languageCode}' is empty",
2181
                $e->getMessage()
2182
            );
2183
2184
            throw $e;
2185
        }
2186
    }
2187
2188
    /**
2189
     * Asserts behaviour necessary for testing ContentFieldValidationException because of
2190
     * field not being valid.
2191
     *
2192
     * @param string $mainLanguageCode
2193
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $structFields
2194
     * @param \eZ\Publish\API\Repository\Values\ContentType\FieldDefinition[] $fieldDefinitions
2195
     *
2196
     * @return mixed
2197
     */
2198
    protected function assertForTestCreateContentThrowsContentFieldValidationException(
2199
        $mainLanguageCode,
2200
        array $structFields,
2201
        array $fieldDefinitions
2202
    ) {
2203
        $repositoryMock = $this->getRepositoryMock();
2204
        /** @var \PHPUnit_Framework_MockObject_MockObject $languageHandlerMock */
2205
        $languageHandlerMock = $this->getPersistenceMock()->contentLanguageHandler();
2206
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
2207
        $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...
2208
        $domainMapperMock = $this->getDomainMapperMock();
2209
        $relationProcessorMock = $this->getRelationProcessorMock();
2210
        $fieldTypeMock = $this->getMock('eZ\\Publish\\SPI\\FieldType\\FieldType');
2211
        $languageCodes = $this->determineLanguageCodesForCreate($mainLanguageCode, $structFields);
2212
        $contentType = new ContentType(
2213
            array(
2214
                'id' => 123,
2215
                'fieldDefinitions' => $fieldDefinitions,
2216
                'nameSchema' => '<nameSchema>',
2217
            )
2218
        );
2219
        $contentCreateStruct = new ContentCreateStruct(
2220
            array(
2221
                'fields' => $structFields,
2222
                'mainLanguageCode' => $mainLanguageCode,
2223
                'contentType' => $contentType,
2224
                'alwaysAvailable' => false,
2225
                'ownerId' => 169,
2226
                'sectionId' => 1,
2227
            )
2228
        );
2229
2230
        $languageHandlerMock->expects($this->any())
2231
            ->method('loadByLanguageCode')
2232
            ->with($this->isType('string'))
2233
            ->will(
2234
                $this->returnCallback(
2235
                    function () {
2236
                        return new Language(array('id' => 4242));
2237
                    }
2238
                )
2239
            );
2240
2241
        $contentTypeServiceMock->expects($this->once())
2242
            ->method('loadContentType')
2243
            ->with($this->equalTo($contentType->id))
2244
            ->will($this->returnValue($contentType));
2245
2246
        $repositoryMock->expects($this->once())
2247
            ->method('getContentTypeService')
2248
            ->will($this->returnValue($contentTypeServiceMock));
2249
2250
        $that = $this;
2251
        $repositoryMock->expects($this->once())
2252
            ->method('canUser')
2253
            ->with(
2254
                $this->equalTo('content'),
2255
                $this->equalTo('create'),
2256
                $this->isInstanceOf('eZ\\Publish\\API\\Repository\\Values\\Content\\ContentCreateStruct'),
2257
                $this->equalTo(array())
2258
            )->will(
2259
                $this->returnCallback(
2260
                    function () use ($that, $contentCreateStruct) {
2261
                        $that->assertEquals($contentCreateStruct, func_get_arg(2));
2262
2263
                        return true;
2264
                    }
2265
                )
2266
            );
2267
2268
        $domainMapperMock->expects($this->once())
2269
            ->method('getUniqueHash')
2270
            ->with($this->isInstanceOf('eZ\\Publish\\API\\Repository\\Values\\Content\\ContentCreateStruct'))
2271
            ->will(
2272
                $this->returnCallback(
2273
                    function ($object) use ($that, $contentCreateStruct) {
2274
                        $that->assertEquals($contentCreateStruct, $object);
2275
2276
                        return 'hash';
2277
                    }
2278
                )
2279
            );
2280
2281
        $this->getFieldTypeRegistryMock()->expects($this->any())
2282
            ->method('getFieldType')
2283
            ->will($this->returnValue($fieldTypeMock));
2284
2285
        $relationProcessorMock
2286
            ->expects($this->any())
2287
            ->method('appendFieldRelations')
2288
            ->with(
2289
                $this->isType('array'),
2290
                $this->isType('array'),
2291
                $this->isInstanceOf('eZ\\Publish\\SPI\\FieldType\\FieldType'),
2292
                $this->isInstanceOf('eZ\\Publish\\Core\\FieldType\\Value'),
2293
                $this->anything()
2294
            );
2295
2296
        $fieldValues = $this->determineValuesForCreate(
2297
            $mainLanguageCode,
2298
            $structFields,
2299
            $fieldDefinitions,
2300
            $languageCodes
2301
        );
2302
        $allFieldErrors = array();
2303
        $validateCount = 0;
2304
        $emptyValue = self::EMPTY_FIELD_VALUE;
2305 View Code Duplication
        foreach ($contentType->getFieldDefinitions() as $fieldDefinition) {
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...
2306
            foreach ($fieldValues[$fieldDefinition->identifier] as $languageCode => $value) {
2307
                $fieldTypeMock->expects($this->at($validateCount++))
2308
                    ->method('acceptValue')
2309
                    ->will(
2310
                        $this->returnCallback(
2311
                            function ($valueString) {
2312
                                return new ValueStub($valueString);
2313
                            }
2314
                        )
2315
                    );
2316
2317
                $fieldTypeMock->expects($this->at($validateCount++))
2318
                    ->method('isEmptyValue')
2319
                    ->will(
2320
                        $this->returnCallback(
2321
                            function (ValueStub $value) use ($emptyValue) {
2322
                                return $emptyValue === (string)$value;
2323
                            }
2324
                        )
2325
                    );
2326
2327
                if (self::EMPTY_FIELD_VALUE === (string)$value) {
2328
                    continue;
2329
                }
2330
2331
                $fieldTypeMock->expects($this->at($validateCount++))
2332
                    ->method('validate')
2333
                    ->with(
2334
                        $this->equalTo($fieldDefinition),
2335
                        $this->equalTo($value)
2336
                    )->will($this->returnArgument(1));
2337
2338
                $allFieldErrors[$fieldDefinition->id][$languageCode] = $value;
2339
            }
2340
        }
2341
2342
        return array($contentCreateStruct, $allFieldErrors);
2343
    }
2344
2345
    public function providerForTestCreateContentThrowsContentFieldValidationException()
2346
    {
2347
        return $this->providerForTestCreateContentNonRedundantFieldSetComplex();
2348
    }
2349
2350
    /**
2351
     * Test for the createContent() method.
2352
     *
2353
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
2354
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForCreate
2355
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
2356
     * @dataProvider providerForTestCreateContentThrowsContentFieldValidationException
2357
     * @expectedException \eZ\Publish\API\Repository\Exceptions\ContentFieldValidationException
2358
     * @expectedExceptionMessage Content fields did not validate
2359
     */
2360
    public function testCreateContentThrowsContentFieldValidationException($mainLanguageCode, $structFields)
2361
    {
2362
        $fieldDefinitions = $this->fixturesForTestCreateContentNonRedundantFieldSetComplex();
2363
        list($contentCreateStruct, $allFieldErrors) =
2364
            $this->assertForTestCreateContentThrowsContentFieldValidationException(
2365
                $mainLanguageCode,
2366
                $structFields,
2367
                $fieldDefinitions
2368
            );
2369
2370
        $mockedService = $this->getPartlyMockedContentService();
2371
2372
        try {
2373
            $mockedService->createContent($contentCreateStruct);
2374
        } catch (ContentFieldValidationException $e) {
2375
            $this->assertEquals($allFieldErrors, $e->getFieldErrors());
2376
            throw $e;
2377
        }
2378
    }
2379
2380
    /**
2381
     * Test for the createContent() method.
2382
     *
2383
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
2384
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForCreate
2385
     * @covers \eZ\Publish\Core\Repository\ContentService::buildSPILocationCreateStructs
2386
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
2387
     */
2388
    public function testCreateContentWithLocations()
2389
    {
2390
        $spiFields = array(
2391
            new SPIField(
2392
                array(
2393
                    'fieldDefinitionId' => 'fieldDefinitionId',
2394
                    'type' => 'fieldTypeIdentifier',
2395
                    'value' => 'defaultValue',
2396
                    'languageCode' => 'eng-US',
2397
                )
2398
            ),
2399
        );
2400
        $fieldDefinitions = array(
2401
            new FieldDefinition(
2402
                array(
2403
                    'id' => 'fieldDefinitionId',
2404
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
2405
                    'isTranslatable' => false,
2406
                    'identifier' => 'identifier',
2407
                    'isRequired' => false,
2408
                    'defaultValue' => 'defaultValue',
2409
                )
2410
            ),
2411
        );
2412
2413
        // Set up a simple case that will pass
2414
        $locationCreateStruct1 = new LocationCreateStruct(array('parentLocationId' => 321));
2415
        $locationCreateStruct2 = new LocationCreateStruct(array('parentLocationId' => 654));
2416
        $locationCreateStructs = array($locationCreateStruct1, $locationCreateStruct2);
2417
        $contentCreateStruct = $this->assertForTestCreateContentNonRedundantFieldSet(
2418
            'eng-US',
2419
            array(),
2420
            $spiFields,
2421
            $fieldDefinitions,
2422
            $locationCreateStructs,
2423
            false,
2424
            // Do not execute
2425
            false
2426
        );
2427
2428
        $repositoryMock = $this->getRepositoryMock();
2429
        $mockedService = $this->getPartlyMockedContentService();
2430
        $locationServiceMock = $this->getLocationServiceMock();
2431
        /** @var \PHPUnit_Framework_MockObject_MockObject $handlerMock */
2432
        $handlerMock = $this->getPersistenceMock()->contentHandler();
2433
        $domainMapperMock = $this->getDomainMapperMock();
2434
        $spiLocationCreateStruct = new SPILocation\CreateStruct();
2435
        $parentLocation = new Location(array('contentInfo' => new ContentInfo(array('sectionId' => 1))));
2436
2437
        $locationServiceMock->expects($this->at(0))
2438
            ->method('loadLocation')
2439
            ->with($this->equalTo(321))
2440
            ->will($this->returnValue($parentLocation));
2441
2442
        $locationServiceMock->expects($this->at(1))
2443
            ->method('loadLocation')
2444
            ->with($this->equalTo(654))
2445
            ->will($this->returnValue($parentLocation));
2446
2447
        $repositoryMock->expects($this->atLeastOnce())
2448
            ->method('getLocationService')
2449
            ->will($this->returnValue($locationServiceMock));
2450
2451
        $domainMapperMock->expects($this->at(1))
2452
            ->method('buildSPILocationCreateStruct')
2453
            ->with(
2454
                $this->equalTo($locationCreateStruct1),
2455
                $this->equalTo($parentLocation),
2456
                $this->equalTo(true),
2457
                $this->equalTo(null),
2458
                $this->equalTo(null)
2459
            )->will($this->returnValue($spiLocationCreateStruct));
2460
2461
        $domainMapperMock->expects($this->at(2))
2462
            ->method('buildSPILocationCreateStruct')
2463
            ->with(
2464
                $this->equalTo($locationCreateStruct2),
2465
                $this->equalTo($parentLocation),
2466
                $this->equalTo(false),
2467
                $this->equalTo(null),
2468
                $this->equalTo(null)
2469
            )->will($this->returnValue($spiLocationCreateStruct));
2470
2471
        $spiContentCreateStruct = new SPIContentCreateStruct(
2472
            array(
2473
                'name' => array(),
2474
                'typeId' => 123,
2475
                'sectionId' => 1,
2476
                'ownerId' => 169,
2477
                'remoteId' => 'hash',
2478
                'fields' => $spiFields,
2479
                'modified' => time(),
2480
                'initialLanguageId' => 4242,
2481
                'locations' => array($spiLocationCreateStruct, $spiLocationCreateStruct),
2482
            )
2483
        );
2484
        $spiContentCreateStruct2 = clone $spiContentCreateStruct;
2485
        ++$spiContentCreateStruct2->modified;
2486
2487
        $spiContent = new SPIContent(
2488
            array(
2489
                'versionInfo' => new SPIContent\VersionInfo(
2490
                    array(
2491
                        'contentInfo' => new SPIContent\ContentInfo(array('id' => 42)),
2492
                        'versionNo' => 7,
2493
                    )
2494
                ),
2495
            )
2496
        );
2497
2498
        $handlerMock->expects($this->once())
2499
            ->method('create')
2500
            ->with($this->logicalOr($spiContentCreateStruct, $spiContentCreateStruct2))
2501
            ->will($this->returnValue($spiContent));
2502
2503
        $domainMapperMock->expects($this->once())
2504
            ->method('buildContentDomainObject')
2505
            ->with(
2506
                $this->isInstanceOf('eZ\\Publish\\SPI\\Persistence\\Content'),
2507
                $this->equalTo(null)
2508
            );
2509
2510
        $repositoryMock->expects($this->once())->method('commit');
2511
2512
        // Execute
2513
        $mockedService->createContent($contentCreateStruct, $locationCreateStructs);
2514
    }
2515
2516
    /**
2517
     * Test for the createContent() method.
2518
     *
2519
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
2520
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForCreate
2521
     * @covers \eZ\Publish\Core\Repository\ContentService::buildSPILocationCreateStructs
2522
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
2523
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
2524
     * @expectedExceptionMessage Multiple LocationCreateStructs with the same parent Location '321' are given
2525
     */
2526
    public function testCreateContentWithLocationsDuplicateUnderParent()
2527
    {
2528
        $fieldDefinitions = array(
2529
            new FieldDefinition(
2530
                array(
2531
                    'id' => 'fieldDefinitionId',
2532
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
2533
                    'isTranslatable' => false,
2534
                    'identifier' => 'identifier',
2535
                    'isRequired' => false,
2536
                    'defaultValue' => 'defaultValue',
2537
                )
2538
            ),
2539
        );
2540
2541
        $repositoryMock = $this->getRepositoryMock();
2542
        $mockedService = $this->getPartlyMockedContentService();
2543
        $locationServiceMock = $this->getLocationServiceMock();
2544
        $contentTypeServiceMock = $this->getContentTypeServiceMock();
2545
        $domainMapperMock = $this->getDomainMapperMock();
2546
        /** @var \PHPUnit_Framework_MockObject_MockObject $languageHandlerMock */
2547
        $languageHandlerMock = $this->getPersistenceMock()->contentLanguageHandler();
2548
        $spiLocationCreateStruct = new SPILocation\CreateStruct();
2549
        $parentLocation = new Location(array('id' => 321));
2550
        $locationCreateStruct = new LocationCreateStruct(array('parentLocationId' => 321));
2551
        $locationCreateStructs = array($locationCreateStruct, clone $locationCreateStruct);
2552
        $contentType = new ContentType(
2553
            array(
2554
                'id' => 123,
2555
                'fieldDefinitions' => $fieldDefinitions,
2556
                'nameSchema' => '<nameSchema>',
2557
            )
2558
        );
2559
        $contentCreateStruct = new ContentCreateStruct(
2560
            array(
2561
                'fields' => array(),
2562
                'mainLanguageCode' => 'eng-US',
2563
                'contentType' => $contentType,
2564
                'alwaysAvailable' => false,
2565
                'ownerId' => 169,
2566
                'sectionId' => 1,
2567
            )
2568
        );
2569
2570
        $languageHandlerMock->expects($this->any())
2571
            ->method('loadByLanguageCode')
2572
            ->with($this->isType('string'))
2573
            ->will(
2574
                $this->returnCallback(
2575
                    function () {
2576
                        return new Language(array('id' => 4242));
2577
                    }
2578
                )
2579
            );
2580
2581
        $contentTypeServiceMock->expects($this->once())
2582
            ->method('loadContentType')
2583
            ->with($this->equalTo($contentType->id))
2584
            ->will($this->returnValue($contentType));
2585
2586
        $repositoryMock->expects($this->once())
2587
            ->method('getContentTypeService')
2588
            ->will($this->returnValue($contentTypeServiceMock));
2589
2590
        $that = $this;
2591
        $repositoryMock->expects($this->once())
2592
            ->method('canUser')
2593
            ->with(
2594
                $this->equalTo('content'),
2595
                $this->equalTo('create'),
2596
                $this->isInstanceOf('eZ\\Publish\\API\\Repository\\Values\\Content\\ContentCreateStruct'),
2597
                $this->equalTo($locationCreateStructs)
2598
            )->will(
2599
                $this->returnCallback(
2600
                    function () use ($that, $contentCreateStruct) {
2601
                        $that->assertEquals($contentCreateStruct, func_get_arg(2));
2602
2603
                        return true;
2604
                    }
2605
                )
2606
            );
2607
2608
        $domainMapperMock->expects($this->once())
2609
            ->method('getUniqueHash')
2610
            ->with($this->isInstanceOf('eZ\\Publish\\API\\Repository\\Values\\Content\\ContentCreateStruct'))
2611
            ->will(
2612
                $this->returnCallback(
2613
                    function ($object) use ($that, $contentCreateStruct) {
2614
                        $that->assertEquals($contentCreateStruct, $object);
2615
2616
                        return 'hash';
2617
                    }
2618
                )
2619
            );
2620
2621
        $locationServiceMock->expects($this->once())
2622
            ->method('loadLocation')
2623
            ->with($this->equalTo(321))
2624
            ->will($this->returnValue($parentLocation));
2625
2626
        $repositoryMock->expects($this->any())
2627
            ->method('getLocationService')
2628
            ->will($this->returnValue($locationServiceMock));
2629
2630
        $domainMapperMock->expects($this->any())
2631
            ->method('buildSPILocationCreateStruct')
2632
            ->with(
2633
                $this->equalTo($locationCreateStruct),
2634
                $this->equalTo($parentLocation),
2635
                $this->equalTo(true),
2636
                $this->equalTo(null),
2637
                $this->equalTo(null)
2638
            )->will($this->returnValue($spiLocationCreateStruct));
2639
2640
        $mockedService->createContent(
2641
            $contentCreateStruct,
2642
            $locationCreateStructs
2643
        );
2644
    }
2645
2646
    /**
2647
     * Test for the createContent() method.
2648
     *
2649
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
2650
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForCreate
2651
     * @covers \eZ\Publish\Core\Repository\ContentService::getDefaultObjectStates
2652
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
2653
     */
2654
    public function testCreateContentObjectStates()
2655
    {
2656
        $spiFields = array(
2657
            new SPIField(
2658
                array(
2659
                    'fieldDefinitionId' => 'fieldDefinitionId',
2660
                    'type' => 'fieldTypeIdentifier',
2661
                    'value' => 'defaultValue',
2662
                    'languageCode' => 'eng-US',
2663
                )
2664
            ),
2665
        );
2666
        $fieldDefinitions = array(
2667
            new FieldDefinition(
2668
                array(
2669
                    'id' => 'fieldDefinitionId',
2670
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
2671
                    'isTranslatable' => false,
2672
                    'identifier' => 'identifier',
2673
                    'isRequired' => false,
2674
                    'defaultValue' => 'defaultValue',
2675
                )
2676
            ),
2677
        );
2678
        $objectStateGroups = array(
0 ignored issues
show
Unused Code introduced by
$objectStateGroups is not used, you could remove the assignment.

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

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

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

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

Loading history...
2679
            new SPIObjectStateGroup(array('id' => 10)),
2680
            new SPIObjectStateGroup(array('id' => 20)),
2681
        );
2682
2683
        // Set up a simple case that will pass
2684
        $contentCreateStruct = $this->assertForTestCreateContentNonRedundantFieldSet(
2685
            'eng-US',
2686
            array(),
2687
            $spiFields,
2688
            $fieldDefinitions,
2689
            array(),
2690
            true,
2691
            // Do not execute
2692
            false
2693
        );
2694
        $timestamp = time();
2695
        $contentCreateStruct->modificationDate = new \DateTime("@{$timestamp}");
2696
2697
        $repositoryMock = $this->getRepositoryMock();
2698
        $mockedService = $this->getPartlyMockedContentService();
2699
        /** @var \PHPUnit_Framework_MockObject_MockObject $handlerMock */
2700
        $handlerMock = $this->getPersistenceMock()->contentHandler();
2701
        $domainMapperMock = $this->getDomainMapperMock();
2702
2703
        $this->mockGetDefaultObjectStates();
2704
        $this->mockSetDefaultObjectStates();
2705
2706
        $spiContentCreateStruct = new SPIContentCreateStruct(
2707
            array(
2708
                'name' => array(),
2709
                'typeId' => 123,
2710
                'sectionId' => 1,
2711
                'ownerId' => 169,
2712
                'remoteId' => 'hash',
2713
                'fields' => $spiFields,
2714
                'modified' => $timestamp,
2715
                'initialLanguageId' => 4242,
2716
                'locations' => array(),
2717
            )
2718
        );
2719
        $spiContentCreateStruct2 = clone $spiContentCreateStruct;
2720
        ++$spiContentCreateStruct2->modified;
2721
2722
        $spiContent = new SPIContent(
2723
            array(
2724
                'versionInfo' => new SPIContent\VersionInfo(
2725
                    array(
2726
                        'contentInfo' => new SPIContent\ContentInfo(array('id' => 42)),
2727
                        'versionNo' => 7,
2728
                    )
2729
                ),
2730
            )
2731
        );
2732
2733
        $handlerMock->expects($this->once())
2734
            ->method('create')
2735
            ->with($this->equalTo($spiContentCreateStruct))
2736
            ->will($this->returnValue($spiContent));
2737
2738
        $domainMapperMock->expects($this->once())
2739
            ->method('buildContentDomainObject')
2740
            ->with(
2741
                $this->isInstanceOf('eZ\\Publish\\SPI\\Persistence\\Content'),
2742
                $this->equalTo(null)
2743
            );
2744
2745
        $repositoryMock->expects($this->once())->method('commit');
2746
2747
        // Execute
2748
        $mockedService->createContent($contentCreateStruct, array());
2749
    }
2750
2751
    /**
2752
     * Test for the createContent() method.
2753
     *
2754
     * @covers \eZ\Publish\Core\Repository\ContentService::getLanguageCodesForCreate
2755
     * @covers \eZ\Publish\Core\Repository\ContentService::mapFieldsForCreate
2756
     * @covers \eZ\Publish\Core\Repository\ContentService::getDefaultObjectStates
2757
     * @covers \eZ\Publish\Core\Repository\ContentService::createContent
2758
     * @dataProvider providerForTestCreateContentThrowsContentValidationExceptionTranslation
2759
     * @expectedException \Exception
2760
     * @expectedExceptionMessage Store failed
2761
     */
2762
    public function testCreateContentWithRollback()
2763
    {
2764
        $fieldDefinitions = array(
2765
            new FieldDefinition(
2766
                array(
2767
                    'id' => 'fieldDefinitionId',
2768
                    'fieldTypeIdentifier' => 'fieldTypeIdentifier',
2769
                    'isTranslatable' => false,
2770
                    'identifier' => 'identifier',
2771
                    'isRequired' => false,
2772
                    'defaultValue' => 'defaultValue',
2773
                )
2774
            ),
2775
        );
2776
2777
        // Setup a simple case that will pass
2778
        $contentCreateStruct = $this->assertForTestCreateContentNonRedundantFieldSet(
2779
            'eng-US',
2780
            array(),
2781
            array(),
2782
            $fieldDefinitions,
2783
            array(),
2784
            false,
2785
            // Do not execute test
2786
            false
2787
        );
2788
2789
        $repositoryMock = $this->getRepositoryMock();
2790
        $repositoryMock->expects($this->never())->method('commit');
2791
        $repositoryMock->expects($this->once())->method('rollback');
2792
2793
        /** @var \PHPUnit_Framework_MockObject_MockObject $contentHandlerMock */
2794
        $contentHandlerMock = $this->getPersistenceMock()->contentHandler();
2795
        $contentHandlerMock->expects($this->once())
2796
            ->method('create')
2797
            ->with($this->anything())
2798
            ->will($this->throwException(new \Exception('Store failed')));
2799
2800
        // Execute
2801
        $this->partlyMockedContentService->createContent($contentCreateStruct, array());
2802
    }
2803
2804
    public function providerForTestUpdateContentThrowsBadStateException()
2805
    {
2806
        return array(
2807
            array(VersionInfo::STATUS_PUBLISHED),
2808
            array(VersionInfo::STATUS_ARCHIVED),
2809
        );
2810
    }
2811
2812
    /**
2813
     * Test for the updateContent() method.
2814
     *
2815
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContent
2816
     * @expectedException \eZ\Publish\API\Repository\Exceptions\BadStateException
2817
     * @dataProvider providerForTestUpdateContentThrowsBadStateException
2818
     */
2819
    public function testUpdateContentThrowsBadStateException($status)
2820
    {
2821
        $mockedService = $this->getPartlyMockedContentService(array('loadContent'));
2822
        $contentUpdateStruct = new ContentUpdateStruct();
2823
        $versionInfo = new VersionInfo(
2824
            array(
2825
                'contentInfo' => new ContentInfo(array('id' => 42)),
2826
                'versionNo' => 7,
2827
                'status' => $status,
2828
            )
2829
        );
2830
        $content = new Content(
2831
            array(
2832
                'versionInfo' => $versionInfo,
2833
                'internalFields' => array(),
2834
            )
2835
        );
2836
2837
        $mockedService->expects($this->once())
2838
            ->method('loadContent')
2839
            ->with(
2840
                $this->equalTo(42),
2841
                $this->equalTo(null),
2842
                $this->equalTo(7)
2843
            )->will(
2844
                $this->returnValue($content)
2845
            );
2846
2847
        $mockedService->updateContent($versionInfo, $contentUpdateStruct);
2848
    }
2849
2850
    /**
2851
     * Test for the updateContent() method.
2852
     *
2853
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContent
2854
     * @expectedException \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
2855
     */
2856
    public function testUpdateContentThrowsUnauthorizedException()
2857
    {
2858
        $repositoryMock = $this->getRepositoryMock();
2859
        $mockedService = $this->getPartlyMockedContentService(array('loadContent'));
2860
        $contentUpdateStruct = new ContentUpdateStruct();
2861
        $versionInfo = new VersionInfo(
2862
            array(
2863
                'contentInfo' => new ContentInfo(array('id' => 42)),
2864
                'versionNo' => 7,
2865
                'status' => VersionInfo::STATUS_DRAFT,
2866
            )
2867
        );
2868
        $content = new Content(
2869
            array(
2870
                'versionInfo' => $versionInfo,
2871
                'internalFields' => array(),
2872
            )
2873
        );
2874
2875
        $mockedService->expects($this->once())
2876
            ->method('loadContent')
2877
            ->with(
2878
                $this->equalTo(42),
2879
                $this->equalTo(null),
2880
                $this->equalTo(7)
2881
            )->will(
2882
                $this->returnValue($content)
2883
            );
2884
2885
        $repositoryMock->expects($this->once())
2886
            ->method('canUser')
2887
            ->with(
2888
                $this->equalTo('content'),
2889
                $this->equalTo('edit'),
2890
                $this->equalTo($content)
2891
            )->will($this->returnValue(false));
2892
2893
        $mockedService->updateContent($versionInfo, $contentUpdateStruct);
2894
    }
2895
2896
    /**
2897
     * @param string $initialLanguageCode
2898
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $structFields
2899
     * @param string[] $existingLanguages
2900
     *
2901
     * @return string[]
2902
     */
2903
    protected function determineLanguageCodesForUpdate($initialLanguageCode, array $structFields, $existingLanguages)
2904
    {
2905
        $languageCodes = array_fill_keys($existingLanguages, true);
2906
        if ($initialLanguageCode !== null) {
2907
            $languageCodes[$initialLanguageCode] = true;
2908
        }
2909
2910 View Code Duplication
        foreach ($structFields as $field) {
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...
2911
            if ($field->languageCode === null || isset($languageCodes[$field->languageCode])) {
2912
                continue;
2913
            }
2914
2915
            $languageCodes[$field->languageCode] = true;
2916
        }
2917
2918
        return array_keys($languageCodes);
2919
    }
2920
2921
    /**
2922
     * @param string $initialLanguageCode
2923
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $structFields
2924
     * @param string $mainLanguageCode
2925
     * @param \eZ\Publish\API\Repository\Values\ContentType\FieldDefinition[] $fieldDefinitions
2926
     *
2927
     * @return array
2928
     */
2929
    protected function mapStructFieldsForUpdate($initialLanguageCode, $structFields, $mainLanguageCode, $fieldDefinitions)
2930
    {
2931
        $initialLanguageCode = $initialLanguageCode ?: $mainLanguageCode;
2932
2933
        $mappedFieldDefinitions = array();
2934
        foreach ($fieldDefinitions as $fieldDefinition) {
2935
            $mappedFieldDefinitions[$fieldDefinition->identifier] = $fieldDefinition;
2936
        }
2937
2938
        $mappedStructFields = array();
2939
        foreach ($structFields as $structField) {
2940
            $identifier = $structField->fieldDefIdentifier;
2941
2942
            if ($structField->languageCode !== null) {
2943
                $languageCode = $structField->languageCode;
2944
            } elseif ($mappedFieldDefinitions[$identifier]->isTranslatable) {
2945
                $languageCode = $initialLanguageCode;
2946
            } else {
2947
                $languageCode = $mainLanguageCode;
2948
            }
2949
2950
            $mappedStructFields[$identifier][$languageCode] = (string)$structField->value;
0 ignored issues
show
Documentation introduced by
The property $value is declared protected in eZ\Publish\API\Repository\Values\Content\Field. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
2951
        }
2952
2953
        return $mappedStructFields;
2954
    }
2955
2956
    /**
2957
     * Returns full, possibly redundant array of field values, indexed by field definition
2958
     * identifier and language code.
2959
     *
2960
     * @param string $initialLanguageCode
2961
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $structFields
2962
     * @param \eZ\Publish\Core\Repository\Values\Content\Content $content
2963
     * @param \eZ\Publish\API\Repository\Values\ContentType\FieldDefinition[] $fieldDefinitions
2964
     * @param array $languageCodes
2965
     *
2966
     * @return array
2967
     */
2968
    protected function determineValuesForUpdate(
2969
        $initialLanguageCode,
2970
        array $structFields,
2971
        Content $content,
2972
        array $fieldDefinitions,
2973
        array $languageCodes
2974
    ) {
2975
        $mainLanguageCode = $content->versionInfo->contentInfo->mainLanguageCode;
2976
2977
        $mappedStructFields = $this->mapStructFieldsForUpdate(
2978
            $initialLanguageCode,
2979
            $structFields,
2980
            $mainLanguageCode,
2981
            $fieldDefinitions
2982
        );
2983
2984
        $values = array();
2985
2986
        foreach ($fieldDefinitions as $fieldDefinition) {
2987
            $identifier = $fieldDefinition->identifier;
2988
            foreach ($languageCodes as $languageCode) {
2989 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...
2990
                    if (isset($mappedStructFields[$identifier][$mainLanguageCode])) {
2991
                        $values[$identifier][$languageCode] = $mappedStructFields[$identifier][$mainLanguageCode];
2992
                    } else {
2993
                        $values[$identifier][$languageCode] = (string)$content->fields[$identifier][$mainLanguageCode];
2994
                    }
2995
                    continue;
2996
                }
2997
2998 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...
2999
                    $values[$identifier][$languageCode] = $mappedStructFields[$identifier][$languageCode];
3000
                    continue;
3001
                }
3002
3003
                if (isset($content->fields[$identifier][$languageCode])) {
3004
                    $values[$identifier][$languageCode] = (string)$content->fields[$identifier][$languageCode];
3005
                    continue;
3006
                }
3007
3008
                $values[$identifier][$languageCode] = (string)$fieldDefinition->defaultValue;
0 ignored issues
show
Documentation introduced by
The property $defaultValue is declared protected in eZ\Publish\API\Repositor...entType\FieldDefinition. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

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