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