Completed
Push — ezp-30646 ( 66adba...cee0f6 )
by
unknown
16:53
created

ContentServiceTest   F

Complexity

Total Complexity 257

Size/Duplication

Total Lines 6751
Duplicated Lines 19.72 %

Coupling/Cohesion

Components 1
Dependencies 34

Importance

Changes 0
Metric Value
wmc 257
lcom 1
cbo 34
dl 1331
loc 6751
rs 0.8
c 0
b 0
f 0

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like ContentServiceTest often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ContentServiceTest, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * File containing the ContentServiceTest 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\API\Repository\Tests;
10
11
use eZ\Publish\API\Repository\LocationService;
12
use eZ\Publish\API\Repository\Values\Content\Content;
13
use eZ\Publish\API\Repository\Exceptions\UnauthorizedException;
14
use eZ\Publish\API\Repository\Values\Content\ContentInfo;
15
use eZ\Publish\API\Repository\Values\Content\ContentMetadataUpdateStruct;
16
use eZ\Publish\API\Repository\Values\Content\Field;
17
use eZ\Publish\API\Repository\Values\Content\Location;
18
use eZ\Publish\API\Repository\Values\Content\URLAlias;
19
use eZ\Publish\API\Repository\Values\Content\Relation;
20
use eZ\Publish\API\Repository\Values\Content\VersionInfo;
21
use eZ\Publish\API\Repository\Values\User\Limitation\SectionLimitation;
22
use eZ\Publish\API\Repository\Values\User\Limitation\LocationLimitation;
23
use eZ\Publish\API\Repository\Values\User\Limitation\ContentTypeLimitation;
24
use eZ\Publish\API\Repository\Exceptions\NotFoundException;
25
use DOMDocument;
26
use Exception;
27
use eZ\Publish\Core\Repository\Values\Content\ContentUpdateStruct;
28
29
/**
30
 * Test case for operations in the ContentService using in memory storage.
31
 *
32
 * @see \eZ\Publish\API\Repository\ContentService
33
 * @group content
34
 */
35
class ContentServiceTest extends BaseContentServiceTest
36
{
37
    /**
38
     * Test for the newContentCreateStruct() method.
39
     *
40
     * @see \eZ\Publish\API\Repository\ContentService::newContentCreateStruct()
41
     * @depends eZ\Publish\API\Repository\Tests\ContentTypeServiceTest::testLoadContentTypeByIdentifier
42
     * @group user
43
     * @group field-type
44
     */
45
    public function testNewContentCreateStruct()
46
    {
47
        $repository = $this->getRepository();
48
49
        /* BEGIN: Use Case */
50
        // Create a content type
51
        $contentTypeService = $repository->getContentTypeService();
52
53
        $contentType = $contentTypeService->loadContentTypeByIdentifier('forum');
54
55
        $contentService = $repository->getContentService();
56
57
        $contentCreate = $contentService->newContentCreateStruct($contentType, 'eng-US');
58
        /* END: Use Case */
59
60
        $this->assertInstanceOf('\\eZ\\Publish\\API\\Repository\\Values\\Content\\ContentCreateStruct', $contentCreate);
61
    }
62
63
    /**
64
     * Test for the createContent() method.
65
     *
66
     * @return \eZ\Publish\API\Repository\Values\Content\Content
67
     *
68
     * @see \eZ\Publish\API\Repository\ContentService::createContent()
69
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testNewContentCreateStruct
70
     * @group user
71
     * @group field-type
72
     */
73
    public function testCreateContent()
74
    {
75
        if ($this->isVersion4()) {
76
            $this->markTestSkipped('This test requires eZ Publish 5');
77
        }
78
79
        $repository = $this->getRepository();
80
81
        /* BEGIN: Use Case */
82
        $contentTypeService = $repository->getContentTypeService();
83
84
        $contentType = $contentTypeService->loadContentTypeByIdentifier('forum');
85
86
        $contentService = $repository->getContentService();
87
88
        $contentCreate = $contentService->newContentCreateStruct($contentType, 'eng-US');
89
        $contentCreate->setField('name', 'My awesome forum');
90
91
        $contentCreate->remoteId = 'abcdef0123456789abcdef0123456789';
92
        $contentCreate->alwaysAvailable = true;
93
94
        $content = $contentService->createContent($contentCreate);
95
        /* END: Use Case */
96
97
        $this->assertInstanceOf('\\eZ\\Publish\\API\\Repository\\Values\\Content\\Content', $content);
98
99
        return $content;
100
    }
101
102
    /**
103
     * Test for the createContent() method.
104
     *
105
     * Tests made for issue #EZP-20955 where Anonymous user is granted access to create content
106
     * and should have access to do that.
107
     *
108
     * @return \eZ\Publish\API\Repository\Values\Content\Content
109
     *
110
     * @see \eZ\Publish\API\Repository\ContentService::createContent()
111
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testNewContentCreateStruct
112
     * @group user
113
     * @group field-type
114
     */
115
    public function testCreateContentAndPublishWithPrivilegedAnonymousUser()
116
    {
117
        if ($this->isVersion4()) {
118
            $this->markTestSkipped('This test requires eZ Publish 5');
119
        }
120
121
        $anonymousUserId = $this->generateId('user', 10);
122
123
        $repository = $this->getRepository();
124
        $contentService = $repository->getContentService();
125
        $contentTypeService = $repository->getContentTypeService();
126
        $locationService = $repository->getLocationService();
127
        $roleService = $repository->getRoleService();
128
129
        // Give Anonymous user role additional rights
130
        $role = $roleService->loadRoleByIdentifier('Anonymous');
131
        $roleDraft = $roleService->createRoleDraft($role);
132
        $policyCreateStruct = $roleService->newPolicyCreateStruct('content', 'create');
133
        $policyCreateStruct->addLimitation(new SectionLimitation(['limitationValues' => [1]]));
134
        $policyCreateStruct->addLimitation(new LocationLimitation(['limitationValues' => [2]]));
135
        $policyCreateStruct->addLimitation(new ContentTypeLimitation(['limitationValues' => [1]]));
136
        $roleDraft = $roleService->addPolicyByRoleDraft($roleDraft, $policyCreateStruct);
137
138
        $policyCreateStruct = $roleService->newPolicyCreateStruct('content', 'publish');
139
        $policyCreateStruct->addLimitation(new SectionLimitation(['limitationValues' => [1]]));
140
        $policyCreateStruct->addLimitation(new LocationLimitation(['limitationValues' => [2]]));
141
        $policyCreateStruct->addLimitation(new ContentTypeLimitation(['limitationValues' => [1]]));
142
        $roleDraft = $roleService->addPolicyByRoleDraft($roleDraft, $policyCreateStruct);
143
        $roleService->publishRoleDraft($roleDraft);
144
145
        // Set Anonymous user as current
146
        $repository->getPermissionResolver()->setCurrentUserReference($repository->getUserService()->loadUser($anonymousUserId));
147
148
        // Create a new content object:
149
        $contentCreate = $contentService->newContentCreateStruct(
150
            $contentTypeService->loadContentTypeByIdentifier('folder'),
151
            'eng-GB'
152
        );
153
154
        $contentCreate->setField('name', 'Folder 1');
155
156
        $content = $contentService->createContent(
157
            $contentCreate,
158
            [$locationService->newLocationCreateStruct(2)]
159
        );
160
161
        $contentService->publishVersion(
162
            $content->getVersionInfo()
163
        );
164
    }
165
166
    /**
167
     * Test for the createContent() method.
168
     *
169
     * @param \eZ\Publish\API\Repository\Values\Content\Content $content
170
     *
171
     * @return \eZ\Publish\API\Repository\Values\Content\Content
172
     *
173
     * @see \eZ\Publish\API\Repository\ContentService::createContent()
174
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContent
175
     */
176
    public function testCreateContentSetsContentInfo($content)
177
    {
178
        $this->assertInstanceOf('\\eZ\\Publish\\API\\Repository\\Values\\Content\\ContentInfo', $content->contentInfo);
179
180
        return $content;
181
    }
182
183
    /**
184
     * Test for the createContent() method.
185
     *
186
     * @param \eZ\Publish\API\Repository\Values\Content\Content $content
187
     *
188
     * @see \eZ\Publish\API\Repository\ContentService::createContent()
189
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentSetsContentInfo
190
     */
191
    public function testCreateContentSetsExpectedContentInfo($content)
192
    {
193
        $this->assertEquals(
194
            [
195
                $content->id,
196
                28, // id of content type "forum"
197
                true,
198
                1,
199
                'abcdef0123456789abcdef0123456789',
200
                'eng-US',
201
                $this->getRepository()->getCurrentUser()->id,
202
                false,
203
                null,
204
                // Main Location id for unpublished Content should be null
205
                null,
206
            ],
207
            [
208
                $content->contentInfo->id,
209
                $content->contentInfo->contentTypeId,
210
                $content->contentInfo->alwaysAvailable,
211
                $content->contentInfo->currentVersionNo,
212
                $content->contentInfo->remoteId,
213
                $content->contentInfo->mainLanguageCode,
214
                $content->contentInfo->ownerId,
215
                $content->contentInfo->published,
216
                $content->contentInfo->publishedDate,
217
                $content->contentInfo->mainLocationId,
218
            ]
219
        );
220
    }
221
222
    /**
223
     * Test for the createContent() method.
224
     *
225
     * @param \eZ\Publish\API\Repository\Values\Content\Content $content
226
     *
227
     * @return \eZ\Publish\API\Repository\Values\Content\Content
228
     *
229
     * @see \eZ\Publish\API\Repository\ContentService::createContent()
230
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContent
231
     */
232
    public function testCreateContentSetsVersionInfo($content)
233
    {
234
        $this->assertInstanceOf('\\eZ\\Publish\\API\\Repository\\Values\\Content\\VersionInfo', $content->getVersionInfo());
235
236
        return $content;
237
    }
238
239
    /**
240
     * Test for the createContent() method.
241
     *
242
     * @param \eZ\Publish\API\Repository\Values\Content\Content $content
243
     *
244
     * @see \eZ\Publish\API\Repository\ContentService::createContent()
245
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentSetsVersionInfo
246
     */
247
    public function testCreateContentSetsExpectedVersionInfo($content)
248
    {
249
        $this->assertEquals(
250
            [
251
                'status' => VersionInfo::STATUS_DRAFT,
252
                'versionNo' => 1,
253
                'creatorId' => $this->getRepository()->getCurrentUser()->id,
254
                'initialLanguageCode' => 'eng-US',
255
            ],
256
            [
257
                'status' => $content->getVersionInfo()->status,
258
                'versionNo' => $content->getVersionInfo()->versionNo,
259
                'creatorId' => $content->getVersionInfo()->creatorId,
260
                'initialLanguageCode' => $content->getVersionInfo()->initialLanguageCode,
261
            ]
262
        );
263
        $this->assertTrue($content->getVersionInfo()->isDraft());
264
        $this->assertFalse($content->getVersionInfo()->isPublished());
265
        $this->assertFalse($content->getVersionInfo()->isArchived());
266
    }
267
268
    /**
269
     * Test for the createContent() method.
270
     *
271
     * @param \eZ\Publish\API\Repository\Values\Content\Content $content
272
     *
273
     * @see \eZ\Publish\API\Repository\ContentService::createContent()
274
     * @depends testCreateContent
275
     */
276
    public function testCreateContentSetsExpectedContentType($content)
277
    {
278
        $contentType = $content->getContentType();
279
280
        $this->assertEquals(
281
            [
282
                $contentType->id,
283
                // Won't match as it's set to true in createContentDraftVersion1()
284
                //$contentType->defaultAlwaysAvailable,
285
                //$contentType->defaultSortField,
286
                //$contentType->defaultSortOrder,
287
            ],
288
            [
289
                $content->contentInfo->contentTypeId,
290
                //$content->contentInfo->alwaysAvailable,
291
                //$location->sortField,
292
                //$location->sortOrder,
293
            ]
294
        );
295
    }
296
297
    /**
298
     * Test for the createContent() method.
299
     *
300
     * @see \eZ\Publish\API\Repository\ContentService::createContent()
301
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContent
302
     */
303
    public function testCreateContentThrowsInvalidArgumentException()
304
    {
305
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\InvalidArgumentException::class);
306
307
        if ($this->isVersion4()) {
308
            $this->markTestSkipped('This test requires eZ Publish 5');
309
        }
310
311
        $repository = $this->getRepository();
312
313
        /* BEGIN: Use Case */
314
        $contentTypeService = $repository->getContentTypeService();
315
        $contentService = $repository->getContentService();
316
317
        $contentType = $contentTypeService->loadContentTypeByIdentifier('forum');
318
319
        $contentCreate1 = $contentService->newContentCreateStruct($contentType, 'eng-US');
320
        $contentCreate1->setField('name', 'An awesome Sidelfingen forum');
321
322
        $contentCreate1->remoteId = 'abcdef0123456789abcdef0123456789';
323
        $contentCreate1->alwaysAvailable = true;
324
325
        $draft = $contentService->createContent($contentCreate1);
326
        $contentService->publishVersion($draft->versionInfo);
327
328
        $contentCreate2 = $contentService->newContentCreateStruct($contentType, 'eng-GB');
329
        $contentCreate2->setField('name', 'An awesome Bielefeld forum');
330
331
        $contentCreate2->remoteId = 'abcdef0123456789abcdef0123456789';
332
        $contentCreate2->alwaysAvailable = false;
333
334
        // This call will fail with an "InvalidArgumentException", because the
335
        // remoteId is already in use.
336
        $contentService->createContent($contentCreate2);
337
        /* END: Use Case */
338
    }
339
340
    /**
341
     * Test for the createContent() method.
342
     *
343
     * @see \eZ\Publish\API\Repository\ContentService::createContent()
344
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContent
345
     */
346
    public function testCreateContentThrowsInvalidArgumentExceptionOnFieldTypeNotAccept()
347
    {
348
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\InvalidArgumentException::class);
349
350
        $repository = $this->getRepository();
351
352
        /* BEGIN: Use Case */
353
        $contentTypeService = $repository->getContentTypeService();
354
        $contentService = $repository->getContentService();
355
356
        $contentType = $contentTypeService->loadContentTypeByIdentifier('forum');
357
358
        $contentCreate = $contentService->newContentCreateStruct($contentType, 'eng-US');
359
        // The name field does only accept strings and null as its values
360
        $contentCreate->setField('name', new \stdClass());
361
362
        // Throws InvalidArgumentException since the name field is filled
363
        // improperly
364
        $draft = $contentService->createContent($contentCreate);
365
        /* END: Use Case */
366
    }
367
368
    /**
369
     * Test for the createContent() method.
370
     *
371
     * @see \eZ\Publish\API\Repository\ContentService::createContent()
372
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContent
373
     */
374
    public function testCreateContentThrowsContentFieldValidationException()
375
    {
376
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\ContentFieldValidationException::class);
377
378
        $repository = $this->getRepository();
379
380
        /* BEGIN: Use Case */
381
        $contentTypeService = $repository->getContentTypeService();
382
        $contentService = $repository->getContentService();
383
384
        $contentType = $contentTypeService->loadContentTypeByIdentifier('folder');
385
386
        $contentCreate1 = $contentService->newContentCreateStruct($contentType, 'eng-US');
387
        $contentCreate1->setField('name', 'An awesome Sidelfingen folder');
388
        // Violates string length constraint
389
        $contentCreate1->setField('short_name', str_repeat('a', 200));
390
391
        // Throws ContentFieldValidationException, since short_name does not pass
392
        // validation of the string length validator
393
        $draft = $contentService->createContent($contentCreate1);
394
        /* END: Use Case */
395
    }
396
397
    /**
398
     * Test for the createContent() method.
399
     *
400
     * @see \eZ\Publish\API\Repository\ContentService::createContent()
401
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContent
402
     */
403
    public function testCreateContentRequiredFieldMissing()
404
    {
405
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\ContentFieldValidationException::class);
406
407
        $repository = $this->getRepository();
408
409
        /* BEGIN: Use Case */
410
        $contentTypeService = $repository->getContentTypeService();
411
        $contentService = $repository->getContentService();
412
413
        $contentType = $contentTypeService->loadContentTypeByIdentifier('forum');
414
415
        $contentCreate1 = $contentService->newContentCreateStruct($contentType, 'eng-US');
416
        // Required field "name" is not set
417
418
        // Throws a ContentFieldValidationException, since a required field is
419
        // missing
420
        $draft = $contentService->createContent($contentCreate1);
421
        /* END: Use Case */
422
    }
423
424
    /**
425
     * Test for the createContent() method.
426
     *
427
     * NOTE: We have bidirectional dependencies between the ContentService and
428
     * the LocationService, so that we cannot use PHPUnit's test dependencies
429
     * here.
430
     *
431
     * @see \eZ\Publish\API\Repository\ContentService::createContent($contentCreateStruct, $locationCreateStructs)
432
     * @depend(s) eZ\Publish\API\Repository\Tests\LocationServiceTest::testCreateLocation
433
     * @depend(s) eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocationByRemoteId
434
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContent
435
     * @group user
436
     */
437
    public function testCreateContentWithLocationCreateParameterDoesNotCreateLocationImmediately()
438
    {
439
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\NotFoundException::class);
440
441
        $repository = $this->getRepository();
442
443
        $locationService = $repository->getLocationService();
444
445
        /* BEGIN: Use Case */
446
        $draft = $this->createContentDraftVersion1();
447
448
        // The location will not have been created, yet, so this throws an
449
        // exception
450
        $location = $locationService->loadLocationByRemoteId(
451
            '0123456789abcdef0123456789abcdef'
452
        );
453
        /* END: Use Case */
454
    }
455
456
    /**
457
     * Test for the createContent() method.
458
     *
459
     * @see \eZ\Publish\API\Repository\ContentService::createContent($contentCreateStruct, $locationCreateStructs)
460
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentWithLocationCreateParameterDoesNotCreateLocationImmediately
461
     */
462
    public function testCreateContentThrowsInvalidArgumentExceptionWithLocationCreateParameter()
463
    {
464
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\InvalidArgumentException::class);
465
466
        $repository = $this->getRepository();
467
468
        $parentLocationId = $this->generateId('location', 56);
469
        /* BEGIN: Use Case */
470
        // $parentLocationId is a valid location ID
471
472
        $contentService = $repository->getContentService();
473
        $contentTypeService = $repository->getContentTypeService();
474
        $locationService = $repository->getLocationService();
475
476
        // Load content type
477
        $contentType = $contentTypeService->loadContentTypeByIdentifier('forum');
478
479
        // Configure new locations
480
        $locationCreate1 = $locationService->newLocationCreateStruct($parentLocationId);
481
482
        $locationCreate1->priority = 23;
483
        $locationCreate1->hidden = true;
484
        $locationCreate1->remoteId = '0123456789abcdef0123456789aaaaaa';
485
        $locationCreate1->sortField = Location::SORT_FIELD_NODE_ID;
486
        $locationCreate1->sortOrder = Location::SORT_ORDER_DESC;
487
488
        $locationCreate2 = $locationService->newLocationCreateStruct($parentLocationId);
489
490
        $locationCreate2->priority = 42;
491
        $locationCreate2->hidden = true;
492
        $locationCreate2->remoteId = '0123456789abcdef0123456789bbbbbb';
493
        $locationCreate2->sortField = Location::SORT_FIELD_NODE_ID;
494
        $locationCreate2->sortOrder = Location::SORT_ORDER_DESC;
495
496
        // Configure new content object
497
        $contentCreate = $contentService->newContentCreateStruct($contentType, 'eng-US');
498
499
        $contentCreate->setField('name', 'A awesome Sindelfingen forum');
500
        $contentCreate->remoteId = 'abcdef0123456789abcdef0123456789';
501
        $contentCreate->alwaysAvailable = true;
502
503
        // Create new content object under the specified location
504
        $draft = $contentService->createContent(
505
            $contentCreate,
506
            [$locationCreate1]
507
        );
508
        $contentService->publishVersion($draft->versionInfo);
509
510
        // This call will fail with an "InvalidArgumentException", because the
511
        // Content remoteId already exists,
512
        $contentService->createContent(
513
            $contentCreate,
514
            [$locationCreate2]
515
        );
516
        /* END: Use Case */
517
    }
518
519
    /**
520
     * Test for the loadContentInfo() method.
521
     *
522
     * @see \eZ\Publish\API\Repository\ContentService::loadContentInfo()
523
     * @group user
524
     */
525
    public function testLoadContentInfo()
526
    {
527
        $repository = $this->getRepository();
528
529
        $mediaFolderId = $this->generateId('object', 41);
530
        /* BEGIN: Use Case */
531
        $contentService = $repository->getContentService();
532
533
        // Load the ContentInfo for "Media" folder
534
        $contentInfo = $contentService->loadContentInfo($mediaFolderId);
535
        /* END: Use Case */
536
537
        $this->assertInstanceOf(
538
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\ContentInfo',
539
            $contentInfo
540
        );
541
542
        return $contentInfo;
543
    }
544
545
    /**
546
     * Test for the returned value of the loadContentInfo() method.
547
     *
548
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentInfo
549
     * @covers \eZ\Publish\API\Repository\ContentService::loadContentInfo
550
     *
551
     * @param \eZ\Publish\API\Repository\Values\Content\ContentInfo $contentInfo
552
     */
553
    public function testLoadContentInfoSetsExpectedContentInfo(ContentInfo $contentInfo)
554
    {
555
        $this->assertPropertiesCorrectUnsorted(
556
            $this->getExpectedMediaContentInfoProperties(),
557
            $contentInfo
558
        );
559
    }
560
561
    /**
562
     * Test for the loadContentInfo() method.
563
     *
564
     * @see \eZ\Publish\API\Repository\ContentService::loadContentInfo()
565
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentInfo
566
     */
567
    public function testLoadContentInfoThrowsNotFoundException()
568
    {
569
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\NotFoundException::class);
570
571
        $repository = $this->getRepository();
572
573
        $nonExistentContentId = $this->generateId('object', self::DB_INT_MAX);
574
        /* BEGIN: Use Case */
575
        $contentService = $repository->getContentService();
576
577
        // This call will fail with a NotFoundException
578
        $contentService->loadContentInfo($nonExistentContentId);
579
        /* END: Use Case */
580
    }
581
582
    /**
583
     * Test for the loadContentInfoList() method.
584
     *
585
     * @see \eZ\Publish\API\Repository\ContentService::loadContentInfoList()
586
     */
587
    public function testLoadContentInfoList()
588
    {
589
        $repository = $this->getRepository();
590
591
        $mediaFolderId = $this->generateId('object', 41);
592
        $contentService = $repository->getContentService();
593
        $list = $contentService->loadContentInfoList([$mediaFolderId]);
594
595
        $this->assertCount(1, $list);
596
        $this->assertEquals([$mediaFolderId], array_keys($list), 'Array key was not content id');
597
        $this->assertInstanceOf(
598
            ContentInfo::class,
599
            $list[$mediaFolderId]
600
        );
601
    }
602
603
    /**
604
     * Test for the loadContentInfoList() method.
605
     *
606
     * @see \eZ\Publish\API\Repository\ContentService::loadContentInfoList()
607
     * @depends testLoadContentInfoList
608
     */
609
    public function testLoadContentInfoListSkipsNotFoundItems()
610
    {
611
        $repository = $this->getRepository();
612
613
        $nonExistentContentId = $this->generateId('object', self::DB_INT_MAX);
614
        $contentService = $repository->getContentService();
615
        $list = $contentService->loadContentInfoList([$nonExistentContentId]);
616
617
        $this->assertCount(0, $list);
618
    }
619
620
    /**
621
     * Test for the loadContentInfoByRemoteId() method.
622
     *
623
     * @see \eZ\Publish\API\Repository\ContentService::loadContentInfoByRemoteId()
624
     */
625
    public function testLoadContentInfoByRemoteId()
626
    {
627
        $repository = $this->getRepository();
628
629
        /* BEGIN: Use Case */
630
        $contentService = $repository->getContentService();
631
632
        // Load the ContentInfo for "Media" folder
633
        $contentInfo = $contentService->loadContentInfoByRemoteId('faaeb9be3bd98ed09f606fc16d144eca');
634
        /* END: Use Case */
635
636
        $this->assertInstanceOf('\\eZ\\Publish\\API\\Repository\\Values\\Content\\ContentInfo', $contentInfo);
637
638
        return $contentInfo;
639
    }
640
641
    /**
642
     * Test for the returned value of the loadContentInfoByRemoteId() method.
643
     *
644
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentInfoByRemoteId
645
     * @covers \eZ\Publish\API\Repository\ContentService::loadContentInfoByRemoteId
646
     *
647
     * @param \eZ\Publish\API\Repository\Values\Content\ContentInfo $contentInfo
648
     */
649
    public function testLoadContentInfoByRemoteIdSetsExpectedContentInfo(ContentInfo $contentInfo)
650
    {
651
        $this->assertPropertiesCorrectUnsorted(
652
            [
653
                'id' => 10,
654
                'contentTypeId' => 4,
655
                'name' => 'Anonymous User',
656
                'sectionId' => 2,
657
                'currentVersionNo' => 2,
658
                'published' => true,
659
                'ownerId' => 14,
660
                'modificationDate' => $this->createDateTime(1072180405),
661
                'publishedDate' => $this->createDateTime(1033920665),
662
                'alwaysAvailable' => 1,
663
                'remoteId' => 'faaeb9be3bd98ed09f606fc16d144eca',
664
                'mainLanguageCode' => 'eng-US',
665
                'mainLocationId' => 45,
666
            ],
667
            $contentInfo
668
        );
669
    }
670
671
    /**
672
     * Test for the loadContentInfoByRemoteId() method.
673
     *
674
     * @see \eZ\Publish\API\Repository\ContentService::loadContentInfoByRemoteId()
675
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentInfoByRemoteId
676
     */
677
    public function testLoadContentInfoByRemoteIdThrowsNotFoundException()
678
    {
679
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\NotFoundException::class);
680
681
        $repository = $this->getRepository();
682
683
        /* BEGIN: Use Case */
684
        $contentService = $repository->getContentService();
685
686
        // This call will fail with a NotFoundException
687
        $contentService->loadContentInfoByRemoteId('abcdefghijklmnopqrstuvwxyz0123456789');
688
        /* END: Use Case */
689
    }
690
691
    /**
692
     * Test for the loadVersionInfo() method.
693
     *
694
     * @see \eZ\Publish\API\Repository\ContentService::loadVersionInfo()
695
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentInfo
696
     * @group user
697
     */
698
    public function testLoadVersionInfo()
699
    {
700
        $repository = $this->getRepository();
701
702
        $mediaFolderId = $this->generateId('object', 41);
703
        /* BEGIN: Use Case */
704
        // $mediaFolderId contains the ID of the "Media" folder
705
706
        $contentService = $repository->getContentService();
707
708
        // Load the ContentInfo for "Media" folder
709
        $contentInfo = $contentService->loadContentInfo($mediaFolderId);
710
711
        // Now load the current version info of the "Media" folder
712
        $versionInfo = $contentService->loadVersionInfo($contentInfo);
713
        /* END: Use Case */
714
715
        $this->assertInstanceOf(
716
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\VersionInfo',
717
            $versionInfo
718
        );
719
    }
720
721
    /**
722
     * Test for the loadVersionInfoById() method.
723
     *
724
     * @see \eZ\Publish\API\Repository\ContentService::loadVersionInfoById()
725
     */
726
    public function testLoadVersionInfoById()
727
    {
728
        $repository = $this->getRepository();
729
730
        $mediaFolderId = $this->generateId('object', 41);
731
        /* BEGIN: Use Case */
732
        // $mediaFolderId contains the ID of the "Media" folder
733
734
        $contentService = $repository->getContentService();
735
736
        // Load the VersionInfo for "Media" folder
737
        $versionInfo = $contentService->loadVersionInfoById($mediaFolderId);
738
        /* END: Use Case */
739
740
        $this->assertInstanceOf(
741
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\VersionInfo',
742
            $versionInfo
743
        );
744
745
        return $versionInfo;
746
    }
747
748
    /**
749
     * Test for the returned value of the loadVersionInfoById() method.
750
     *
751
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadVersionInfoById
752
     * @covers \eZ\Publish\Core\Repository\ContentService::loadVersionInfoById
753
     *
754
     * @param \eZ\Publish\API\Repository\Values\Content\VersionInfo $versionInfo
755
     */
756
    public function testLoadVersionInfoByIdSetsExpectedVersionInfo(VersionInfo $versionInfo)
757
    {
758
        $this->assertPropertiesCorrect(
759
            [
760
                'names' => [
761
                    'eng-US' => 'Media',
762
                ],
763
                'contentInfo' => new ContentInfo($this->getExpectedMediaContentInfoProperties()),
764
                'id' => 472,
765
                'versionNo' => 1,
766
                'modificationDate' => $this->createDateTime(1060695457),
767
                'creatorId' => 14,
768
                'creationDate' => $this->createDateTime(1060695450),
769
                'status' => VersionInfo::STATUS_PUBLISHED,
770
                'initialLanguageCode' => 'eng-US',
771
                'languageCodes' => [
772
                    'eng-US',
773
                ],
774
            ],
775
            $versionInfo
776
        );
777
        $this->assertTrue($versionInfo->isPublished());
778
        $this->assertFalse($versionInfo->isDraft());
779
        $this->assertFalse($versionInfo->isArchived());
780
    }
781
782
    /**
783
     * Test for the loadVersionInfoById() method.
784
     *
785
     * @see \eZ\Publish\API\Repository\ContentService::loadVersionInfoById()
786
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadVersionInfoById
787
     */
788
    public function testLoadVersionInfoByIdThrowsNotFoundException()
789
    {
790
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\NotFoundException::class);
791
792
        $repository = $this->getRepository();
793
794
        $nonExistentContentId = $this->generateId('object', self::DB_INT_MAX);
795
        /* BEGIN: Use Case */
796
        $contentService = $repository->getContentService();
797
798
        // This call will fail with a "NotFoundException"
799
        $contentService->loadVersionInfoById($nonExistentContentId);
800
        /* END: Use Case */
801
    }
802
803
    /**
804
     * Test for the loadContentByContentInfo() method.
805
     *
806
     * @see \eZ\Publish\API\Repository\ContentService::loadContentByContentInfo()
807
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentInfo
808
     */
809
    public function testLoadContentByContentInfo()
810
    {
811
        $repository = $this->getRepository();
812
813
        $mediaFolderId = $this->generateId('object', 41);
814
        /* BEGIN: Use Case */
815
        // $mediaFolderId contains the ID of the "Media" folder
816
817
        $contentService = $repository->getContentService();
818
819
        // Load the ContentInfo for "Media" folder
820
        $contentInfo = $contentService->loadContentInfo($mediaFolderId);
821
822
        // Now load the current content version for the info instance
823
        $content = $contentService->loadContentByContentInfo($contentInfo);
824
        /* END: Use Case */
825
826
        $this->assertInstanceOf(
827
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\Content',
828
            $content
829
        );
830
    }
831
832
    /**
833
     * Test for the loadContentByVersionInfo() method.
834
     *
835
     * @see \eZ\Publish\API\Repository\ContentService::loadContentByVersionInfo()
836
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadVersionInfo
837
     */
838
    public function testLoadContentByVersionInfo()
839
    {
840
        $repository = $this->getRepository();
841
842
        $mediaFolderId = $this->generateId('object', 41);
843
        /* BEGIN: Use Case */
844
        // $mediaFolderId contains the ID of the "Media" folder
845
846
        $contentService = $repository->getContentService();
847
848
        // Load the ContentInfo for "Media" folder
849
        $contentInfo = $contentService->loadContentInfo($mediaFolderId);
850
851
        // Load the current VersionInfo
852
        $versionInfo = $contentService->loadVersionInfo($contentInfo);
853
854
        // Now load the current content version for the info instance
855
        $content = $contentService->loadContentByVersionInfo($versionInfo);
856
        /* END: Use Case */
857
858
        $this->assertInstanceOf(
859
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\Content',
860
            $content
861
        );
862
    }
863
864
    /**
865
     * Test for the loadContent() method.
866
     *
867
     * @see \eZ\Publish\API\Repository\ContentService::loadContent()
868
     * @group user
869
     * @group field-type
870
     */
871
    public function testLoadContent()
872
    {
873
        $repository = $this->getRepository();
874
875
        $mediaFolderId = $this->generateId('object', 41);
876
        /* BEGIN: Use Case */
877
        // $mediaFolderId contains the ID of the "Media" folder
878
879
        $contentService = $repository->getContentService();
880
881
        // Load the Content for "Media" folder, any language and current version
882
        $content = $contentService->loadContent($mediaFolderId);
883
        /* END: Use Case */
884
885
        $this->assertInstanceOf(
886
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\Content',
887
            $content
888
        );
889
    }
890
891
    /**
892
     * Test for the loadContent() method.
893
     *
894
     * @see \eZ\Publish\API\Repository\ContentService::loadContent()
895
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContent
896
     */
897
    public function testLoadContentThrowsNotFoundException()
898
    {
899
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\NotFoundException::class);
900
901
        $repository = $this->getRepository();
902
903
        $nonExistentContentId = $this->generateId('object', self::DB_INT_MAX);
904
        /* BEGIN: Use Case */
905
        $contentService = $repository->getContentService();
906
907
        // This call will fail with a "NotFoundException"
908
        $contentService->loadContent($nonExistentContentId);
909
        /* END: Use Case */
910
    }
911
912
    /**
913
     * Data provider for testLoadContentByRemoteId().
914
     *
915
     * @return array
916
     */
917
    public function contentRemoteIdVersionLanguageProvider()
918
    {
919
        return [
920
            ['f5c88a2209584891056f987fd965b0ba', null, null],
921
            ['f5c88a2209584891056f987fd965b0ba', ['eng-US'], null],
922
            ['f5c88a2209584891056f987fd965b0ba', null, 1],
923
            ['f5c88a2209584891056f987fd965b0ba', ['eng-US'], 1],
924
            ['a6e35cbcb7cd6ae4b691f3eee30cd262', null, null],
925
            ['a6e35cbcb7cd6ae4b691f3eee30cd262', ['eng-US'], null],
926
            ['a6e35cbcb7cd6ae4b691f3eee30cd262', null, 1],
927
            ['a6e35cbcb7cd6ae4b691f3eee30cd262', ['eng-US'], 1],
928
        ];
929
    }
930
931
    /**
932
     * Test for the loadContentByRemoteId() method.
933
     *
934
     * @covers \eZ\Publish\API\Repository\ContentService::loadContentByRemoteId
935
     * @dataProvider contentRemoteIdVersionLanguageProvider
936
     *
937
     * @param string $remoteId
938
     * @param array|null $languages
939
     * @param int $versionNo
940
     */
941
    public function testLoadContentByRemoteId($remoteId, $languages, $versionNo)
942
    {
943
        $repository = $this->getRepository();
944
945
        $contentService = $repository->getContentService();
946
947
        $content = $contentService->loadContentByRemoteId($remoteId, $languages, $versionNo);
948
949
        $this->assertInstanceOf(
950
            Content::class,
951
            $content
952
        );
953
954
        $this->assertEquals($remoteId, $content->contentInfo->remoteId);
955
        if ($languages !== null) {
956
            $this->assertEquals($languages, $content->getVersionInfo()->languageCodes);
957
        }
958
        $this->assertEquals($versionNo ?: 1, $content->getVersionInfo()->versionNo);
959
    }
960
961
    /**
962
     * Test for the loadContentByRemoteId() method.
963
     *
964
     * @see \eZ\Publish\API\Repository\ContentService::loadContentByRemoteId()
965
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentByRemoteId
966
     */
967
    public function testLoadContentByRemoteIdThrowsNotFoundException()
968
    {
969
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\NotFoundException::class);
970
971
        $repository = $this->getRepository();
972
973
        /* BEGIN: Use Case */
974
        $contentService = $repository->getContentService();
975
976
        // This call will fail with a "NotFoundException", because no content
977
        // object exists for the given remoteId
978
        $contentService->loadContentByRemoteId('a1b1c1d1e1f1a2b2c2d2e2f2a3b3c3d3');
979
        /* END: Use Case */
980
    }
981
982
    /**
983
     * Test for the publishVersion() method.
984
     *
985
     * @return \eZ\Publish\API\Repository\Values\Content\Content
986
     *
987
     * @see \eZ\Publish\API\Repository\ContentService::publishVersion()
988
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContent
989
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentInfo
990
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadVersionInfo
991
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentWithLocationCreateParameterDoesNotCreateLocationImmediately
992
     * @group user
993
     * @group field-type
994
     */
995
    public function testPublishVersion()
996
    {
997
        $time = time();
998
        /* BEGIN: Use Case */
999
        $content = $this->createContentVersion1();
1000
        /* END: Use Case */
1001
1002
        $this->assertInstanceOf(Content::class, $content);
1003
        $this->assertTrue($content->contentInfo->published);
1004
        $this->assertEquals(VersionInfo::STATUS_PUBLISHED, $content->versionInfo->status);
1005
        $this->assertGreaterThanOrEqual($time, $content->contentInfo->publishedDate->getTimestamp());
1006
        $this->assertGreaterThanOrEqual($time, $content->contentInfo->modificationDate->getTimestamp());
1007
        $this->assertTrue($content->versionInfo->isPublished());
1008
        $this->assertFalse($content->versionInfo->isDraft());
1009
        $this->assertFalse($content->versionInfo->isArchived());
1010
1011
        return $content;
1012
    }
1013
1014
    /**
1015
     * Test for the publishVersion() method.
1016
     *
1017
     * @param \eZ\Publish\API\Repository\Values\Content\Content $content
1018
     *
1019
     * @see \eZ\Publish\API\Repository\ContentService::publishVersion()
1020
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersion
1021
     */
1022
    public function testPublishVersionSetsExpectedContentInfo($content)
1023
    {
1024
        $this->assertEquals(
1025
            [
1026
                $content->id,
1027
                true,
1028
                1,
1029
                'abcdef0123456789abcdef0123456789',
1030
                'eng-US',
1031
                $this->getRepository()->getCurrentUser()->id,
1032
                true,
1033
            ],
1034
            [
1035
                $content->contentInfo->id,
1036
                $content->contentInfo->alwaysAvailable,
1037
                $content->contentInfo->currentVersionNo,
1038
                $content->contentInfo->remoteId,
1039
                $content->contentInfo->mainLanguageCode,
1040
                $content->contentInfo->ownerId,
1041
                $content->contentInfo->published,
1042
            ]
1043
        );
1044
1045
        $this->assertNotNull($content->contentInfo->mainLocationId);
1046
        $date = new \DateTime('1984/01/01');
1047
        $this->assertGreaterThan(
1048
            $date->getTimestamp(),
1049
            $content->contentInfo->publishedDate->getTimestamp()
1050
        );
1051
    }
1052
1053
    /**
1054
     * Test for the publishVersion() method.
1055
     *
1056
     * @param \eZ\Publish\API\Repository\Values\Content\Content $content
1057
     *
1058
     * @see \eZ\Publish\API\Repository\ContentService::publishVersion()
1059
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersion
1060
     */
1061
    public function testPublishVersionSetsExpectedVersionInfo($content)
1062
    {
1063
        $this->assertEquals(
1064
            [
1065
                $this->getRepository()->getCurrentUser()->id,
1066
                'eng-US',
1067
                VersionInfo::STATUS_PUBLISHED,
1068
                1,
1069
            ],
1070
            [
1071
                $content->getVersionInfo()->creatorId,
1072
                $content->getVersionInfo()->initialLanguageCode,
1073
                $content->getVersionInfo()->status,
1074
                $content->getVersionInfo()->versionNo,
1075
            ]
1076
        );
1077
1078
        $date = new \DateTime('1984/01/01');
1079
        $this->assertGreaterThan(
1080
            $date->getTimestamp(),
1081
            $content->getVersionInfo()->modificationDate->getTimestamp()
1082
        );
1083
1084
        $this->assertNotNull($content->getVersionInfo()->modificationDate);
1085
        $this->assertTrue($content->getVersionInfo()->isPublished());
1086
        $this->assertFalse($content->getVersionInfo()->isDraft());
1087
        $this->assertFalse($content->getVersionInfo()->isArchived());
1088
    }
1089
1090
    /**
1091
     * Test for the publishVersion() method.
1092
     *
1093
     * @param \eZ\Publish\API\Repository\Values\Content\Content $content
1094
     *
1095
     * @see \eZ\Publish\API\Repository\ContentService::publishVersion()
1096
     * @depends testPublishVersion
1097
     */
1098
    public function testPublishVersionSetsExpectedContentType($content)
1099
    {
1100
        $contentType = $content->getContentType();
1101
1102
        $this->assertEquals(
1103
            [
1104
                $contentType->id,
1105
                // won't be a match as it's set to true in createContentDraftVersion1()
1106
                //$contentType->defaultAlwaysAvailable,
1107
                //$contentType->defaultSortField,
1108
                //$contentType->defaultSortOrder,
1109
            ],
1110
            [
1111
                $content->contentInfo->contentTypeId,
1112
                //$content->contentInfo->alwaysAvailable,
1113
                //$location->sortField,
1114
                //$location->sortOrder,
1115
            ]
1116
        );
1117
    }
1118
1119
    /**
1120
     * Test for the publishVersion() method.
1121
     *
1122
     * @return \eZ\Publish\API\Repository\Values\Content\Content
1123
     *
1124
     * @see \eZ\Publish\API\Repository\ContentService::publishVersion()
1125
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentWithLocationCreateParameterDoesNotCreateLocationImmediately
1126
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersion
1127
     */
1128
    public function testPublishVersionCreatesLocationsDefinedOnCreate()
1129
    {
1130
        $repository = $this->getRepository();
1131
1132
        /* BEGIN: Use Case */
1133
        $content = $this->createContentVersion1();
1134
        /* END: Use Case */
1135
1136
        $locationService = $repository->getLocationService();
1137
        $location = $locationService->loadLocationByRemoteId(
1138
            '0123456789abcdef0123456789abcdef'
1139
        );
1140
1141
        $this->assertEquals(
1142
            $location->getContentInfo(),
1143
            $content->getVersionInfo()->getContentInfo()
1144
        );
1145
1146
        return [$content, $location];
1147
    }
1148
1149
    /**
1150
     * Test for the publishVersion() method.
1151
     *
1152
     * @see \eZ\Publish\API\Repository\ContentService::publishVersion()
1153
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersionCreatesLocationsDefinedOnCreate
1154
     */
1155
    public function testCreateContentWithLocationCreateParameterCreatesExpectedLocation(array $testData)
1156
    {
1157
        /** @var \eZ\Publish\API\Repository\Values\Content\Content $content */
1158
        /** @var \eZ\Publish\API\Repository\Values\Content\Location $location */
1159
        list($content, $location) = $testData;
1160
1161
        $parentLocationId = $this->generateId('location', 56);
1162
        $parentLocation = $this->getRepository()->getLocationService()->loadLocation($parentLocationId);
1163
        $mainLocationId = $content->getVersionInfo()->getContentInfo()->mainLocationId;
1164
1165
        $this->assertPropertiesCorrect(
1166
            [
1167
                'id' => $mainLocationId,
1168
                'priority' => 23,
1169
                'hidden' => true,
1170
                'invisible' => true,
1171
                'remoteId' => '0123456789abcdef0123456789abcdef',
1172
                'parentLocationId' => $parentLocationId,
1173
                'pathString' => $parentLocation->pathString . $mainLocationId . '/',
1174
                'depth' => $parentLocation->depth + 1,
1175
                'sortField' => Location::SORT_FIELD_NODE_ID,
1176
                'sortOrder' => Location::SORT_ORDER_DESC,
1177
            ],
1178
            $location
1179
        );
1180
    }
1181
1182
    /**
1183
     * Test for the publishVersion() method.
1184
     *
1185
     * @see \eZ\Publish\API\Repository\ContentService::publishVersion()
1186
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersion
1187
     */
1188
    public function testPublishVersionThrowsBadStateException()
1189
    {
1190
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\BadStateException::class);
1191
1192
        $repository = $this->getRepository();
1193
1194
        $contentService = $repository->getContentService();
1195
1196
        /* BEGIN: Use Case */
1197
        $draft = $this->createContentDraftVersion1();
1198
1199
        // Publish the content draft
1200
        $contentService->publishVersion($draft->getVersionInfo());
1201
1202
        // This call will fail with a "BadStateException", because the version
1203
        // is already published.
1204
        $contentService->publishVersion($draft->getVersionInfo());
1205
        /* END: Use Case */
1206
    }
1207
1208
    /**
1209
     * Test that publishVersion() does not affect publishedDate (assuming previous version exists).
1210
     *
1211
     * @covers \eZ\Publish\API\Repository\ContentService::publishVersion
1212
     */
1213
    public function testPublishVersionDoesNotChangePublishedDate()
1214
    {
1215
        $repository = $this->getRepository();
1216
1217
        $contentService = $repository->getContentService();
1218
1219
        $publishedContent = $this->createContentVersion1();
1220
1221
        // force timestamps to differ
1222
        sleep(1);
1223
1224
        $contentDraft = $contentService->createContentDraft($publishedContent->contentInfo);
1225
        $contentUpdateStruct = $contentService->newContentUpdateStruct();
1226
        $contentUpdateStruct->setField('name', 'New name');
1227
        $contentDraft = $contentService->updateContent($contentDraft->versionInfo, $contentUpdateStruct);
1228
        $republishedContent = $contentService->publishVersion($contentDraft->versionInfo);
1229
1230
        $this->assertEquals(
1231
            $publishedContent->contentInfo->publishedDate->getTimestamp(),
1232
            $republishedContent->contentInfo->publishedDate->getTimestamp()
1233
        );
1234
        $this->assertGreaterThan(
1235
            $publishedContent->contentInfo->modificationDate->getTimestamp(),
1236
            $republishedContent->contentInfo->modificationDate->getTimestamp()
1237
        );
1238
    }
1239
1240
    /**
1241
     * Test for the createContentDraft() method.
1242
     *
1243
     * @return \eZ\Publish\API\Repository\Values\Content\Content
1244
     *
1245
     * @see \eZ\Publish\API\Repository\ContentService::createContentDraft()
1246
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersion
1247
     * @group user
1248
     */
1249
    public function testCreateContentDraft()
1250
    {
1251
        $repository = $this->getRepository();
1252
1253
        $contentService = $repository->getContentService();
1254
1255
        /* BEGIN: Use Case */
1256
        $content = $this->createContentVersion1();
1257
1258
        // Now we create a new draft from the published content
1259
        $draftedContent = $contentService->createContentDraft($content->contentInfo);
1260
        /* END: Use Case */
1261
1262
        $this->assertInstanceOf(
1263
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\Content',
1264
            $draftedContent
1265
        );
1266
1267
        return $draftedContent;
1268
    }
1269
1270
    /**
1271
     * Test for the createContentDraft() method.
1272
     *
1273
     * Test that editor has access to edit own draft.
1274
     * Note: Editors have access to version_read, which is needed to load content drafts.
1275
     *
1276
     * @see \eZ\Publish\API\Repository\ContentService::createContentDraft()
1277
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersion
1278
     * @group user
1279
     */
1280
    public function testCreateContentDraftAndLoadAccess()
1281
    {
1282
        $repository = $this->getRepository();
1283
1284
        /* BEGIN: Use Case */
1285
        $user = $this->createUserVersion1();
1286
1287
        // Set new editor as user
1288
        $repository->setCurrentUser($user);
1289
1290
        // Create draft
1291
        $draft = $this->createContentDraftVersion1(2, 'folder');
1292
1293
        // Try to load the draft
1294
        $contentService = $repository->getContentService();
1295
        $loadedDraft = $contentService->loadContent($draft->id);
1296
1297
        /* END: Use Case */
1298
1299
        $this->assertEquals($draft->id, $loadedDraft->id);
1300
    }
1301
1302
    /**
1303
     * Test for the createContentDraft() method.
1304
     *
1305
     * @param \eZ\Publish\API\Repository\Values\Content\Content $draft
1306
     *
1307
     * @see \eZ\Publish\API\Repository\ContentService::createContentDraft()
1308
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentDraft
1309
     */
1310
    public function testCreateContentDraftSetsExpectedProperties($draft)
1311
    {
1312
        $this->assertEquals(
1313
            [
1314
                'fieldCount' => 2,
1315
                'relationCount' => 0,
1316
            ],
1317
            [
1318
                'fieldCount' => count($draft->getFields()),
1319
                'relationCount' => count($this->getRepository()->getContentService()->loadRelations($draft->getVersionInfo())),
1320
            ]
1321
        );
1322
    }
1323
1324
    /**
1325
     * Test for the createContentDraft() method.
1326
     *
1327
     * @param \eZ\Publish\API\Repository\Values\Content\Content $draft
1328
     *
1329
     * @see \eZ\Publish\API\Repository\ContentService::createContentDraft()
1330
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentDraft
1331
     */
1332
    public function testCreateContentDraftSetsContentInfo($draft)
1333
    {
1334
        $contentInfo = $draft->contentInfo;
1335
1336
        $this->assertEquals(
1337
            [
1338
                $draft->id,
1339
                true,
1340
                1,
1341
                'eng-US',
1342
                $this->getRepository()->getCurrentUser()->id,
1343
                'abcdef0123456789abcdef0123456789',
1344
                1,
1345
            ],
1346
            [
1347
                $contentInfo->id,
1348
                $contentInfo->alwaysAvailable,
1349
                $contentInfo->currentVersionNo,
1350
                $contentInfo->mainLanguageCode,
1351
                $contentInfo->ownerId,
1352
                $contentInfo->remoteId,
1353
                $contentInfo->sectionId,
1354
            ]
1355
        );
1356
    }
1357
1358
    /**
1359
     * Test for the createContentDraft() method.
1360
     *
1361
     * @param \eZ\Publish\API\Repository\Values\Content\Content $draft
1362
     *
1363
     * @see \eZ\Publish\API\Repository\ContentService::createContentDraft()
1364
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentDraft
1365
     */
1366
    public function testCreateContentDraftSetsVersionInfo($draft)
1367
    {
1368
        $versionInfo = $draft->getVersionInfo();
1369
1370
        $this->assertEquals(
1371
            [
1372
                'creatorId' => $this->getRepository()->getCurrentUser()->id,
1373
                'initialLanguageCode' => 'eng-US',
1374
                'languageCodes' => [0 => 'eng-US'],
1375
                'status' => VersionInfo::STATUS_DRAFT,
1376
                'versionNo' => 2,
1377
            ],
1378
            [
1379
                'creatorId' => $versionInfo->creatorId,
1380
                'initialLanguageCode' => $versionInfo->initialLanguageCode,
1381
                'languageCodes' => $versionInfo->languageCodes,
1382
                'status' => $versionInfo->status,
1383
                'versionNo' => $versionInfo->versionNo,
1384
            ]
1385
        );
1386
        $this->assertTrue($versionInfo->isDraft());
1387
        $this->assertFalse($versionInfo->isPublished());
1388
        $this->assertFalse($versionInfo->isArchived());
1389
    }
1390
1391
    /**
1392
     * Test for the createContentDraft() method.
1393
     *
1394
     * @param \eZ\Publish\API\Repository\Values\Content\Content $draft
1395
     *
1396
     * @see \eZ\Publish\API\Repository\ContentService::createContentDraft()
1397
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentDraft
1398
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadVersionInfo
1399
     */
1400
    public function testCreateContentDraftLoadVersionInfoStillLoadsPublishedVersion($draft)
1401
    {
1402
        $repository = $this->getRepository();
1403
1404
        $contentService = $repository->getContentService();
1405
1406
        /* BEGIN: Use Case */
1407
        $content = $this->createContentVersion1();
1408
1409
        // Now we create a new draft from the published content
1410
        $contentService->createContentDraft($content->contentInfo);
1411
1412
        // This call will still load the published version
1413
        $versionInfoPublished = $contentService->loadVersionInfo($content->contentInfo);
1414
        /* END: Use Case */
1415
1416
        $this->assertEquals(1, $versionInfoPublished->versionNo);
1417
    }
1418
1419
    /**
1420
     * Test for the createContentDraft() method.
1421
     *
1422
     * @see \eZ\Publish\API\Repository\ContentService::createContentDraft()
1423
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContent
1424
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentDraft
1425
     */
1426
    public function testCreateContentDraftLoadContentStillLoadsPublishedVersion()
1427
    {
1428
        $repository = $this->getRepository();
1429
1430
        $contentService = $repository->getContentService();
1431
1432
        /* BEGIN: Use Case */
1433
        $content = $this->createContentVersion1();
1434
1435
        // Now we create a new draft from the published content
1436
        $contentService->createContentDraft($content->contentInfo);
1437
1438
        // This call will still load the published content version
1439
        $contentPublished = $contentService->loadContent($content->id);
1440
        /* END: Use Case */
1441
1442
        $this->assertEquals(1, $contentPublished->getVersionInfo()->versionNo);
1443
    }
1444
1445
    /**
1446
     * Test for the createContentDraft() method.
1447
     *
1448
     * @see \eZ\Publish\API\Repository\ContentService::createContentDraft()
1449
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentByRemoteId
1450
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentDraft
1451
     */
1452
    public function testCreateContentDraftLoadContentByRemoteIdStillLoadsPublishedVersion()
1453
    {
1454
        $repository = $this->getRepository();
1455
1456
        $contentService = $repository->getContentService();
1457
1458
        /* BEGIN: Use Case */
1459
        $content = $this->createContentVersion1();
1460
1461
        // Now we create a new draft from the published content
1462
        $contentService->createContentDraft($content->contentInfo);
1463
1464
        // This call will still load the published content version
1465
        $contentPublished = $contentService->loadContentByRemoteId('abcdef0123456789abcdef0123456789');
1466
        /* END: Use Case */
1467
1468
        $this->assertEquals(1, $contentPublished->getVersionInfo()->versionNo);
1469
    }
1470
1471
    /**
1472
     * Test for the createContentDraft() method.
1473
     *
1474
     * @see \eZ\Publish\API\Repository\ContentService::createContentDraft()
1475
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentByContentInfo
1476
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentDraft
1477
     */
1478
    public function testCreateContentDraftLoadContentByContentInfoStillLoadsPublishedVersion()
1479
    {
1480
        $repository = $this->getRepository();
1481
1482
        $contentService = $repository->getContentService();
1483
1484
        /* BEGIN: Use Case */
1485
        $content = $this->createContentVersion1();
1486
1487
        // Now we create a new draft from the published content
1488
        $contentService->createContentDraft($content->contentInfo);
1489
1490
        // This call will still load the published content version
1491
        $contentPublished = $contentService->loadContentByContentInfo($content->contentInfo);
1492
        /* END: Use Case */
1493
1494
        $this->assertEquals(1, $contentPublished->getVersionInfo()->versionNo);
1495
    }
1496
1497
    /**
1498
     * Test for the newContentUpdateStruct() method.
1499
     *
1500
     * @covers \eZ\Publish\API\Repository\ContentService::newContentUpdateStruct
1501
     * @group user
1502
     */
1503
    public function testNewContentUpdateStruct()
1504
    {
1505
        $repository = $this->getRepository();
1506
1507
        /* BEGIN: Use Case */
1508
        $contentService = $repository->getContentService();
1509
1510
        $updateStruct = $contentService->newContentUpdateStruct();
1511
        /* END: Use Case */
1512
1513
        $this->assertInstanceOf(
1514
            ContentUpdateStruct::class,
1515
            $updateStruct
1516
        );
1517
1518
        $this->assertPropertiesCorrect(
1519
            [
1520
                'initialLanguageCode' => null,
1521
                'fields' => [],
1522
            ],
1523
            $updateStruct
1524
        );
1525
    }
1526
1527
    /**
1528
     * Test for the updateContent() method.
1529
     *
1530
     * @return \eZ\Publish\API\Repository\Values\Content\Content
1531
     *
1532
     * @see \eZ\Publish\API\Repository\ContentService::updateContent()
1533
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testNewContentUpdateStruct
1534
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentDraft
1535
     * @group user
1536
     * @group field-type
1537
     */
1538
    public function testUpdateContent()
1539
    {
1540
        /* BEGIN: Use Case */
1541
        $draftVersion2 = $this->createUpdatedDraftVersion2();
1542
        /* END: Use Case */
1543
1544
        $this->assertInstanceOf(
1545
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\Content',
1546
            $draftVersion2
1547
        );
1548
1549
        $this->assertEquals(
1550
            $this->generateId('user', 10),
1551
            $draftVersion2->versionInfo->creatorId,
1552
            'creatorId is not properly set on new Version'
1553
        );
1554
1555
        return $draftVersion2;
1556
    }
1557
1558
    /**
1559
     * Test for the updateContent_WithDifferentUser() method.
1560
     *
1561
     * @return \eZ\Publish\API\Repository\Values\Content\Content
1562
     *
1563
     * @see \eZ\Publish\API\Repository\ContentService::updateContent()
1564
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testNewContentUpdateStruct
1565
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentDraft
1566
     * @group user
1567
     * @group field-type
1568
     */
1569
    public function testUpdateContentWithDifferentUser()
1570
    {
1571
        /* BEGIN: Use Case */
1572
        $arrayWithDraftVersion2 = $this->createUpdatedDraftVersion2NotAdmin();
1573
        /* END: Use Case */
1574
1575
        $this->assertInstanceOf(
1576
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\Content',
1577
            $arrayWithDraftVersion2[0]
1578
        );
1579
1580
        $this->assertEquals(
1581
            $this->generateId('user', $arrayWithDraftVersion2[1]),
1582
            $arrayWithDraftVersion2[0]->versionInfo->creatorId,
1583
            'creatorId is not properly set on new Version'
1584
        );
1585
1586
        return $arrayWithDraftVersion2[0];
1587
    }
1588
1589
    /**
1590
     * Test for the updateContent() method.
1591
     *
1592
     * @param \eZ\Publish\API\Repository\Values\Content\Content $content
1593
     *
1594
     * @see \eZ\Publish\API\Repository\ContentService::updateContent()
1595
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContent
1596
     */
1597
    public function testUpdateContentSetsExpectedFields($content)
1598
    {
1599
        $actual = $this->normalizeFields($content->getFields());
1600
1601
        $expected = [
1602
            new Field(
1603
                [
1604
                    'id' => 0,
1605
                    'value' => true,
1606
                    'languageCode' => 'eng-GB',
1607
                    'fieldDefIdentifier' => 'description',
1608
                    'fieldTypeIdentifier' => 'ezrichtext',
1609
                ]
1610
            ),
1611
            new Field(
1612
                [
1613
                    'id' => 0,
1614
                    'value' => true,
1615
                    'languageCode' => 'eng-US',
1616
                    'fieldDefIdentifier' => 'description',
1617
                    'fieldTypeIdentifier' => 'ezrichtext',
1618
                ]
1619
            ),
1620
            new Field(
1621
                [
1622
                    'id' => 0,
1623
                    'value' => true,
1624
                    'languageCode' => 'eng-GB',
1625
                    'fieldDefIdentifier' => 'name',
1626
                    'fieldTypeIdentifier' => 'ezstring',
1627
                ]
1628
            ),
1629
            new Field(
1630
                [
1631
                    'id' => 0,
1632
                    'value' => true,
1633
                    'languageCode' => 'eng-US',
1634
                    'fieldDefIdentifier' => 'name',
1635
                    'fieldTypeIdentifier' => 'ezstring',
1636
                ]
1637
            ),
1638
        ];
1639
1640
        $this->assertEquals($expected, $actual);
1641
    }
1642
1643
    /**
1644
     * Test for the updateContent() method.
1645
     *
1646
     * @see \eZ\Publish\API\Repository\ContentService::updateContent()
1647
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContent
1648
     */
1649
    public function testUpdateContentThrowsBadStateException()
1650
    {
1651
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\BadStateException::class);
1652
1653
        $repository = $this->getRepository();
1654
1655
        $contentService = $repository->getContentService();
1656
1657
        /* BEGIN: Use Case */
1658
        $content = $this->createContentVersion1();
1659
1660
        // Now create an update struct and modify some fields
1661
        $contentUpdateStruct = $contentService->newContentUpdateStruct();
1662
        $contentUpdateStruct->setField('title', 'An awesome² story about ezp.');
1663
        $contentUpdateStruct->setField('title', 'An awesome²³ story about ezp.', 'eng-GB');
1664
1665
        $contentUpdateStruct->initialLanguageCode = 'eng-US';
1666
1667
        // This call will fail with a "BadStateException", because $publishedContent
1668
        // is not a draft.
1669
        $contentService->updateContent(
1670
            $content->getVersionInfo(),
1671
            $contentUpdateStruct
1672
        );
1673
        /* END: Use Case */
1674
    }
1675
1676
    /**
1677
     * Test for the updateContent() method.
1678
     *
1679
     * @see \eZ\Publish\API\Repository\ContentService::updateContent()
1680
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContent
1681
     */
1682
    public function testUpdateContentThrowsInvalidArgumentExceptionWhenFieldTypeDoesNotAccept()
1683
    {
1684
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\InvalidArgumentException::class);
1685
1686
        $repository = $this->getRepository();
1687
1688
        $contentService = $repository->getContentService();
1689
1690
        /* BEGIN: Use Case */
1691
        $draft = $this->createContentDraftVersion1();
1692
1693
        // Now create an update struct and modify some fields
1694
        $contentUpdateStruct = $contentService->newContentUpdateStruct();
1695
        // The name field does not accept a stdClass object as its input
1696
        $contentUpdateStruct->setField('name', new \stdClass(), 'eng-US');
1697
1698
        // Throws an InvalidArgumentException, since the value for field "name"
1699
        // is not accepted
1700
        $contentService->updateContent(
1701
            $draft->getVersionInfo(),
1702
            $contentUpdateStruct
1703
        );
1704
        /* END: Use Case */
1705
    }
1706
1707
    /**
1708
     * Test for the updateContent() method.
1709
     *
1710
     * @see \eZ\Publish\API\Repository\ContentService::updateContent()
1711
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContent
1712
     */
1713
    public function testUpdateContentWhenMandatoryFieldIsEmpty()
1714
    {
1715
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\ContentFieldValidationException::class);
1716
1717
        $repository = $this->getRepository();
1718
1719
        $contentService = $repository->getContentService();
1720
1721
        /* BEGIN: Use Case */
1722
        $draft = $this->createContentDraftVersion1();
1723
1724
        // Now create an update struct and set a mandatory field to null
1725
        $contentUpdateStruct = $contentService->newContentUpdateStruct();
1726
        $contentUpdateStruct->setField('name', null);
1727
1728
        // Don't set this, then the above call without languageCode will fail
1729
        $contentUpdateStruct->initialLanguageCode = 'eng-US';
1730
1731
        // This call will fail with a "ContentFieldValidationException", because the
1732
        // mandatory "name" field is empty.
1733
        $contentService->updateContent(
1734
            $draft->getVersionInfo(),
1735
            $contentUpdateStruct
1736
        );
1737
        /* END: Use Case */
1738
    }
1739
1740
    /**
1741
     * Test for the updateContent() method.
1742
     *
1743
     * @see \eZ\Publish\API\Repository\ContentService::updateContent()
1744
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContent
1745
     */
1746
    public function testUpdateContentThrowsContentFieldValidationException()
1747
    {
1748
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\ContentFieldValidationException::class);
1749
1750
        $repository = $this->getRepository();
1751
1752
        /* BEGIN: Use Case */
1753
        $contentTypeService = $repository->getContentTypeService();
1754
        $contentService = $repository->getContentService();
1755
1756
        $contentType = $contentTypeService->loadContentTypeByIdentifier('folder');
1757
1758
        $contentCreate = $contentService->newContentCreateStruct($contentType, 'eng-US');
1759
        $contentCreate->setField('name', 'An awesome Sidelfingen folder');
1760
1761
        $draft = $contentService->createContent($contentCreate);
1762
1763
        $contentUpdate = $contentService->newContentUpdateStruct();
1764
        // Violates string length constraint
1765
        $contentUpdate->setField('short_name', str_repeat('a', 200), 'eng-US');
1766
1767
        // Throws ContentFieldValidationException because the string length
1768
        // validation of the field "short_name" fails
1769
        $contentService->updateContent($draft->getVersionInfo(), $contentUpdate);
1770
        /* END: Use Case */
1771
    }
1772
1773
    /**
1774
     * Test for the updateContent() method.
1775
     *
1776
     * @covers \eZ\Publish\API\Repository\ContentService::updateContent()
1777
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContent
1778
     */
1779
    public function testUpdateContentValidatorIgnoresRequiredFieldsOfNotUpdatedLanguages()
1780
    {
1781
        $repository = $this->getRepository();
1782
        /* BEGIN: Use Case */
1783
        $contentTypeService = $repository->getContentTypeService();
1784
        $contentType = $contentTypeService->loadContentTypeByIdentifier('folder');
1785
1786
        // Create multilangual content
1787
        $contentService = $repository->getContentService();
1788
        $contentCreate = $contentService->newContentCreateStruct($contentType, 'eng-US');
1789
        $contentCreate->setField('name', 'An awesome Sidelfingen folder', 'eng-US');
1790
        $contentCreate->setField('name', 'An awesome Sidelfingen folder', 'eng-GB');
1791
1792
        $contentDraft = $contentService->createContent($contentCreate);
1793
1794
        // 2. Update content type definition
1795
        $contentTypeDraft = $contentTypeService->createContentTypeDraft($contentType);
1796
1797
        $fieldDefinition = $contentType->getFieldDefinition('description');
1798
        $fieldDefinitionUpdate = $contentTypeService->newFieldDefinitionUpdateStruct();
1799
        $fieldDefinitionUpdate->identifier = 'description';
1800
        $fieldDefinitionUpdate->isRequired = true;
1801
1802
        $contentTypeService->updateFieldDefinition(
1803
            $contentTypeDraft,
1804
            $fieldDefinition,
1805
            $fieldDefinitionUpdate
1806
        );
1807
        $contentTypeService->publishContentTypeDraft($contentTypeDraft);
1808
1809
        // 3. Update only eng-US translation
1810
        $description = new DOMDocument();
1811
        $description->loadXML(<<<XML
1812
<?xml version="1.0" encoding="UTF-8"?>
1813
<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ezxhtml="http://ez.no/xmlns/ezpublish/docbook/xhtml" xmlns:ezcustom="http://ez.no/xmlns/ezpublish/docbook/custom" version="5.0-variant ezpublish-1.0">
1814
    <para>Lorem ipsum dolor</para>
1815
</section>
1816
XML
1817
        );
1818
1819
        $contentUpdate = $contentService->newContentUpdateStruct();
1820
        $contentUpdate->setField('name', 'An awesome Sidelfingen folder (updated)', 'eng-US');
1821
        $contentUpdate->setField('description', $description);
1822
1823
        $contentService->updateContent($contentDraft->getVersionInfo(), $contentUpdate);
1824
        /* END: Use Case */
1825
    }
1826
1827
    /**
1828
     * Test for the updateContent() method.
1829
     *
1830
     * @see \eZ\Publish\API\Repository\ContentService::updateContent()
1831
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContent
1832
     */
1833
    public function testUpdateContentWithNotUpdatingMandatoryField()
1834
    {
1835
        $repository = $this->getRepository();
1836
1837
        $contentService = $repository->getContentService();
1838
1839
        /* BEGIN: Use Case */
1840
        $draft = $this->createContentDraftVersion1();
1841
1842
        // Now create an update struct which does not overwrite mandatory
1843
        // fields
1844
        $contentUpdateStruct = $contentService->newContentUpdateStruct();
1845
        $contentUpdateStruct->setField(
1846
            'description',
1847
            '<?xml version="1.0" encoding="UTF-8"?><section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0-variant ezpublish-1.0"/>'
1848
        );
1849
1850
        // Don't set this, then the above call without languageCode will fail
1851
        $contentUpdateStruct->initialLanguageCode = 'eng-US';
1852
1853
        // This will only update the "description" field in the "eng-US"
1854
        // language
1855
        $updatedDraft = $contentService->updateContent(
1856
            $draft->getVersionInfo(),
1857
            $contentUpdateStruct
1858
        );
1859
        /* END: Use Case */
1860
1861
        foreach ($updatedDraft->getFields() as $field) {
1862
            if ($field->languageCode === 'eng-US' && $field->fieldDefIdentifier === 'name' && $field->value !== null) {
1863
                // Found field
1864
                return;
1865
            }
1866
        }
1867
        $this->fail(
1868
            'Field with identifier "name" in language "eng-US" could not be found or has empty value.'
1869
        );
1870
    }
1871
1872
    /**
1873
     * Test for the createContentDraft() method.
1874
     *
1875
     * @see \eZ\Publish\API\Repository\ContentService::createContentDraft($contentInfo, $versionInfo)
1876
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContent
1877
     */
1878
    public function testCreateContentDraftWithSecondParameter()
1879
    {
1880
        $repository = $this->getRepository();
1881
1882
        $contentService = $repository->getContentService();
1883
1884
        /* BEGIN: Use Case */
1885
        $contentVersion2 = $this->createContentVersion2();
1886
1887
        // Now we create a new draft from the initial version
1888
        $draftedContentReloaded = $contentService->createContentDraft(
1889
            $contentVersion2->contentInfo,
1890
            $contentVersion2->getVersionInfo()
1891
        );
1892
        /* END: Use Case */
1893
1894
        $this->assertEquals(3, $draftedContentReloaded->getVersionInfo()->versionNo);
1895
    }
1896
1897
    /**
1898
     * Test for the createContentDraft() method with third parameter.
1899
     *
1900
     * @covers \eZ\Publish\Core\Repository\ContentService::createContentDraft
1901
     */
1902
    public function testCreateContentDraftWithThirdParameter()
1903
    {
1904
        $repository = $this->getRepository();
1905
1906
        $contentService = $repository->getContentService();
1907
1908
        $content = $contentService->loadContent(4);
1909
        $user = $this->createUserVersion1();
1910
1911
        $draftContent = $contentService->createContentDraft(
1912
            $content->contentInfo,
1913
            $content->getVersionInfo(),
1914
            $user
1915
        );
1916
1917
        $this->assertInstanceOf(
1918
            Content::class,
1919
            $draftContent
1920
        );
1921
    }
1922
1923
    /**
1924
     * Test for the publishVersion() method.
1925
     *
1926
     * @see \eZ\Publish\API\Repository\ContentService::publishVersion()
1927
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersion
1928
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContent
1929
     */
1930
    public function testPublishVersionFromContentDraft()
1931
    {
1932
        $repository = $this->getRepository();
1933
1934
        $contentService = $repository->getContentService();
1935
1936
        /* BEGIN: Use Case */
1937
        $contentVersion2 = $this->createContentVersion2();
1938
        /* END: Use Case */
1939
1940
        $versionInfo = $contentService->loadVersionInfo($contentVersion2->contentInfo);
1941
1942
        $this->assertEquals(
1943
            [
1944
                'status' => VersionInfo::STATUS_PUBLISHED,
1945
                'versionNo' => 2,
1946
            ],
1947
            [
1948
                'status' => $versionInfo->status,
1949
                'versionNo' => $versionInfo->versionNo,
1950
            ]
1951
        );
1952
        $this->assertTrue($versionInfo->isPublished());
1953
        $this->assertFalse($versionInfo->isDraft());
1954
        $this->assertFalse($versionInfo->isArchived());
1955
    }
1956
1957
    /**
1958
     * Test for the publishVersion() method.
1959
     *
1960
     * @see \eZ\Publish\API\Repository\ContentService::publishVersion()
1961
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersionFromContentDraft
1962
     */
1963
    public function testPublishVersionFromContentDraftArchivesOldVersion()
1964
    {
1965
        $repository = $this->getRepository();
1966
1967
        $contentService = $repository->getContentService();
1968
1969
        /* BEGIN: Use Case */
1970
        $contentVersion2 = $this->createContentVersion2();
1971
        /* END: Use Case */
1972
1973
        $versionInfo = $contentService->loadVersionInfo($contentVersion2->contentInfo, 1);
1974
1975
        $this->assertEquals(
1976
            [
1977
                'status' => VersionInfo::STATUS_ARCHIVED,
1978
                'versionNo' => 1,
1979
            ],
1980
            [
1981
                'status' => $versionInfo->status,
1982
                'versionNo' => $versionInfo->versionNo,
1983
            ]
1984
        );
1985
        $this->assertTrue($versionInfo->isArchived());
1986
        $this->assertFalse($versionInfo->isDraft());
1987
        $this->assertFalse($versionInfo->isPublished());
1988
    }
1989
1990
    /**
1991
     * Test for the publishVersion() method.
1992
     *
1993
     * @see \eZ\Publish\API\Repository\ContentService::publishVersion()
1994
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersionFromContentDraft
1995
     */
1996
    public function testPublishVersionFromContentDraftUpdatesContentInfoCurrentVersion()
1997
    {
1998
        /* BEGIN: Use Case */
1999
        $contentVersion2 = $this->createContentVersion2();
2000
        /* END: Use Case */
2001
2002
        $this->assertEquals(2, $contentVersion2->contentInfo->currentVersionNo);
2003
    }
2004
2005
    /**
2006
     * Test for the publishVersion() method.
2007
     *
2008
     * @see \eZ\Publish\API\Repository\ContentService::publishVersion()
2009
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersionFromContentDraft
2010
     */
2011
    public function testPublishVersionFromOldContentDraftArchivesNewerVersionNo()
2012
    {
2013
        $repository = $this->getRepository();
2014
2015
        $contentService = $repository->getContentService();
2016
2017
        /* BEGIN: Use Case */
2018
        $content = $this->createContentVersion1();
2019
2020
        // Create a new draft with versionNo = 2
2021
        $draftedContentVersion2 = $contentService->createContentDraft($content->contentInfo);
2022
2023
        // Create another new draft with versionNo = 3
2024
        $draftedContentVersion3 = $contentService->createContentDraft($content->contentInfo);
2025
2026
        // Publish draft with versionNo = 3
2027
        $contentService->publishVersion($draftedContentVersion3->getVersionInfo());
2028
2029
        // Publish the first draft with versionNo = 2
2030
        // currentVersionNo is now 2, versionNo 3 will be archived
2031
        $publishedDraft = $contentService->publishVersion($draftedContentVersion2->getVersionInfo());
2032
        /* END: Use Case */
2033
2034
        $this->assertEquals(2, $publishedDraft->contentInfo->currentVersionNo);
2035
    }
2036
2037
    /**
2038
     * Test for the publishVersion() method, and that it creates limited archives.
2039
     *
2040
     * @todo Adapt this when per content type archive limited is added on repository Content Type model.
2041
     * @see \eZ\Publish\API\Repository\ContentService::publishVersion()
2042
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersionFromContentDraft
2043
     */
2044
    public function testPublishVersionNotCreatingUnlimitedArchives()
2045
    {
2046
        $repository = $this->getRepository();
2047
2048
        $contentService = $repository->getContentService();
2049
2050
        $content = $this->createContentVersion1();
2051
2052
        // load first to make sure list gets updated also (cache)
2053
        $versionInfoList = $contentService->loadVersions($content->contentInfo);
2054
        $this->assertCount(1, $versionInfoList);
2055
        $this->assertEquals(1, $versionInfoList[0]->versionNo);
2056
2057
        // Create a new draft with versionNo = 2
2058
        $draftedContentVersion = $contentService->createContentDraft($content->contentInfo);
2059
        $contentService->publishVersion($draftedContentVersion->getVersionInfo());
2060
2061
        // Create a new draft with versionNo = 3
2062
        $draftedContentVersion = $contentService->createContentDraft($content->contentInfo);
2063
        $contentService->publishVersion($draftedContentVersion->getVersionInfo());
2064
2065
        // Create a new draft with versionNo = 4
2066
        $draftedContentVersion = $contentService->createContentDraft($content->contentInfo);
2067
        $contentService->publishVersion($draftedContentVersion->getVersionInfo());
2068
2069
        // Create a new draft with versionNo = 5
2070
        $draftedContentVersion = $contentService->createContentDraft($content->contentInfo);
2071
        $contentService->publishVersion($draftedContentVersion->getVersionInfo());
2072
2073
        // Create a new draft with versionNo = 6
2074
        $draftedContentVersion = $contentService->createContentDraft($content->contentInfo);
2075
        $contentService->publishVersion($draftedContentVersion->getVersionInfo());
2076
2077
        // Create a new draft with versionNo = 7
2078
        $draftedContentVersion = $contentService->createContentDraft($content->contentInfo);
2079
        $contentService->publishVersion($draftedContentVersion->getVersionInfo());
2080
2081
        $versionInfoList = $contentService->loadVersions($content->contentInfo);
2082
2083
        $this->assertCount(6, $versionInfoList);
2084
        $this->assertEquals(2, $versionInfoList[0]->versionNo);
2085
        $this->assertEquals(7, $versionInfoList[5]->versionNo);
2086
2087
        $this->assertEquals(
2088
            [
2089
                VersionInfo::STATUS_ARCHIVED,
2090
                VersionInfo::STATUS_ARCHIVED,
2091
                VersionInfo::STATUS_ARCHIVED,
2092
                VersionInfo::STATUS_ARCHIVED,
2093
                VersionInfo::STATUS_ARCHIVED,
2094
                VersionInfo::STATUS_PUBLISHED,
2095
            ],
2096
            [
2097
                $versionInfoList[0]->status,
2098
                $versionInfoList[1]->status,
2099
                $versionInfoList[2]->status,
2100
                $versionInfoList[3]->status,
2101
                $versionInfoList[4]->status,
2102
                $versionInfoList[5]->status,
2103
            ]
2104
        );
2105
    }
2106
2107
    /**
2108
     * Test for the newContentMetadataUpdateStruct() method.
2109
     *
2110
     * @covers \eZ\Publish\API\Repository\ContentService::newContentMetadataUpdateStruct
2111
     * @group user
2112
     */
2113
    public function testNewContentMetadataUpdateStruct()
2114
    {
2115
        $repository = $this->getRepository();
2116
2117
        /* BEGIN: Use Case */
2118
        $contentService = $repository->getContentService();
2119
2120
        // Creates a new metadata update struct
2121
        $metadataUpdate = $contentService->newContentMetadataUpdateStruct();
2122
2123
        foreach ($metadataUpdate as $propertyName => $propertyValue) {
2124
            $this->assertNull($propertyValue, "Property '{$propertyName}' initial value should be null'");
2125
        }
2126
2127
        $metadataUpdate->remoteId = 'aaaabbbbccccddddeeeeffff11112222';
2128
        $metadataUpdate->mainLanguageCode = 'eng-GB';
2129
        $metadataUpdate->alwaysAvailable = false;
2130
        /* END: Use Case */
2131
2132
        $this->assertInstanceOf(
2133
            ContentMetadataUpdateStruct::class,
2134
            $metadataUpdate
2135
        );
2136
    }
2137
2138
    /**
2139
     * Test for the updateContentMetadata() method.
2140
     *
2141
     * @return \eZ\Publish\API\Repository\Values\Content\Content
2142
     *
2143
     * @see \eZ\Publish\API\Repository\ContentService::updateContentMetadata()
2144
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersion
2145
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testNewContentMetadataUpdateStruct
2146
     * @group user
2147
     */
2148
    public function testUpdateContentMetadata()
2149
    {
2150
        $repository = $this->getRepository();
2151
2152
        $contentService = $repository->getContentService();
2153
2154
        /* BEGIN: Use Case */
2155
        $content = $this->createContentVersion1();
2156
2157
        // Creates a metadata update struct
2158
        $metadataUpdate = $contentService->newContentMetadataUpdateStruct();
2159
2160
        $metadataUpdate->remoteId = 'aaaabbbbccccddddeeeeffff11112222';
2161
        $metadataUpdate->mainLanguageCode = 'eng-GB';
2162
        $metadataUpdate->alwaysAvailable = false;
2163
        $metadataUpdate->publishedDate = $this->createDateTime(441759600); // 1984/01/01
2164
        $metadataUpdate->modificationDate = $this->createDateTime(441759600); // 1984/01/01
2165
2166
        // Update the metadata of the published content object
2167
        $content = $contentService->updateContentMetadata(
2168
            $content->contentInfo,
2169
            $metadataUpdate
2170
        );
2171
        /* END: Use Case */
2172
2173
        $this->assertInstanceOf(
2174
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\Content',
2175
            $content
2176
        );
2177
2178
        return $content;
2179
    }
2180
2181
    /**
2182
     * Test for the updateContentMetadata() method.
2183
     *
2184
     * @param \eZ\Publish\API\Repository\Values\Content\Content $content
2185
     *
2186
     * @see \eZ\Publish\API\Repository\ContentService::updateContentMetadata()
2187
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContentMetadata
2188
     */
2189
    public function testUpdateContentMetadataSetsExpectedProperties($content)
2190
    {
2191
        $contentInfo = $content->contentInfo;
2192
2193
        $this->assertEquals(
2194
            [
2195
                'remoteId' => 'aaaabbbbccccddddeeeeffff11112222',
2196
                'sectionId' => $this->generateId('section', 1),
2197
                'alwaysAvailable' => false,
2198
                'currentVersionNo' => 1,
2199
                'mainLanguageCode' => 'eng-GB',
2200
                'modificationDate' => $this->createDateTime(441759600),
2201
                'ownerId' => $this->getRepository()->getCurrentUser()->id,
2202
                'published' => true,
2203
                'publishedDate' => $this->createDateTime(441759600),
2204
            ],
2205
            [
2206
                'remoteId' => $contentInfo->remoteId,
2207
                'sectionId' => $contentInfo->sectionId,
2208
                'alwaysAvailable' => $contentInfo->alwaysAvailable,
2209
                'currentVersionNo' => $contentInfo->currentVersionNo,
2210
                'mainLanguageCode' => $contentInfo->mainLanguageCode,
2211
                'modificationDate' => $contentInfo->modificationDate,
2212
                'ownerId' => $contentInfo->ownerId,
2213
                'published' => $contentInfo->published,
2214
                'publishedDate' => $contentInfo->publishedDate,
2215
            ]
2216
        );
2217
    }
2218
2219
    /**
2220
     * Test for the updateContentMetadata() method.
2221
     *
2222
     * @param \eZ\Publish\API\Repository\Values\Content\Content $content
2223
     *
2224
     * @see \eZ\Publish\API\Repository\ContentService::updateContentMetadata()
2225
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContentMetadata
2226
     */
2227
    public function testUpdateContentMetadataNotUpdatesContentVersion($content)
2228
    {
2229
        $this->assertEquals(1, $content->getVersionInfo()->versionNo);
2230
    }
2231
2232
    /**
2233
     * Test for the updateContentMetadata() method.
2234
     *
2235
     * @covers \eZ\Publish\API\Repository\ContentService::updateContentMetadata()
2236
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContentMetadata
2237
     */
2238
    public function testUpdateContentMetadataThrowsInvalidArgumentExceptionOnDuplicateRemoteId()
2239
    {
2240
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\InvalidArgumentException::class);
2241
2242
        $repository = $this->getRepository();
2243
2244
        $contentService = $repository->getContentService();
2245
2246
        /* BEGIN: Use Case */
2247
        // RemoteId of the "Media" page of an eZ Publish demo installation
2248
        $mediaRemoteId = 'a6e35cbcb7cd6ae4b691f3eee30cd262';
2249
2250
        $content = $this->createContentVersion1();
2251
2252
        // Creates a metadata update struct
2253
        $metadataUpdate = $contentService->newContentMetadataUpdateStruct();
2254
        $metadataUpdate->remoteId = $mediaRemoteId;
2255
2256
        // This call will fail with an "InvalidArgumentException", because the
2257
        // specified remoteId is already used by the "Media" page.
2258
        $contentService->updateContentMetadata(
2259
            $content->contentInfo,
2260
            $metadataUpdate
2261
        );
2262
        /* END: Use Case */
2263
    }
2264
2265
    /**
2266
     * Test for the updateContentMetadata() method.
2267
     *
2268
     * @covers \eZ\Publish\Core\Repository\ContentService::updateContentMetadata
2269
     */
2270
    public function testUpdateContentMetadataThrowsInvalidArgumentExceptionOnNoMetadataPropertiesSet()
2271
    {
2272
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\InvalidArgumentException::class);
2273
2274
        $repository = $this->getRepository();
2275
2276
        $contentService = $repository->getContentService();
2277
2278
        $contentInfo = $contentService->loadContentInfo(4);
2279
        $contentMetadataUpdateStruct = $contentService->newContentMetadataUpdateStruct();
2280
2281
        // Throws an exception because no properties are set in $contentMetadataUpdateStruct
2282
        $contentService->updateContentMetadata($contentInfo, $contentMetadataUpdateStruct);
2283
    }
2284
2285
    /**
2286
     * Test for the deleteContent() method.
2287
     *
2288
     * @see \eZ\Publish\API\Repository\ContentService::deleteContent()
2289
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersionFromContentDraft
2290
     */
2291
    public function testDeleteContent()
2292
    {
2293
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\NotFoundException::class);
2294
2295
        $repository = $this->getRepository();
2296
2297
        $contentService = $repository->getContentService();
2298
        $locationService = $repository->getLocationService();
2299
2300
        /* BEGIN: Use Case */
2301
        $contentVersion2 = $this->createContentVersion2();
2302
2303
        // Load the locations for this content object
2304
        $locations = $locationService->loadLocations($contentVersion2->contentInfo);
2305
2306
        // This will delete the content, all versions and the associated locations
2307
        $contentService->deleteContent($contentVersion2->contentInfo);
2308
        /* END: Use Case */
2309
2310
        foreach ($locations as $location) {
2311
            $locationService->loadLocation($location->id);
2312
        }
2313
    }
2314
2315
    /**
2316
     * Test for the deleteContent() method.
2317
     *
2318
     * Test for issue EZP-21057:
2319
     * "contentService: Unable to delete a content with an empty file attribute"
2320
     *
2321
     * @see \eZ\Publish\API\Repository\ContentService::deleteContent()
2322
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersionFromContentDraft
2323
     */
2324
    public function testDeleteContentWithEmptyBinaryField()
2325
    {
2326
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\NotFoundException::class);
2327
2328
        $repository = $this->getRepository();
2329
2330
        $contentService = $repository->getContentService();
2331
        $locationService = $repository->getLocationService();
2332
2333
        /* BEGIN: Use Case */
2334
        $contentVersion = $this->createContentVersion1EmptyBinaryField();
2335
2336
        // Load the locations for this content object
2337
        $locations = $locationService->loadLocations($contentVersion->contentInfo);
2338
2339
        // This will delete the content, all versions and the associated locations
2340
        $contentService->deleteContent($contentVersion->contentInfo);
2341
        /* END: Use Case */
2342
2343
        foreach ($locations as $location) {
2344
            $locationService->loadLocation($location->id);
2345
        }
2346
    }
2347
2348
    /**
2349
     * Test for the loadContentDrafts() method.
2350
     *
2351
     * @see \eZ\Publish\API\Repository\ContentService::loadContentDrafts()
2352
     */
2353
    public function testLoadContentDraftsReturnsEmptyArrayByDefault()
2354
    {
2355
        $repository = $this->getRepository();
2356
2357
        /* BEGIN: Use Case */
2358
        $contentService = $repository->getContentService();
2359
2360
        $contentDrafts = $contentService->loadContentDrafts();
2361
        /* END: Use Case */
2362
2363
        $this->assertSame([], $contentDrafts);
2364
    }
2365
2366
    /**
2367
     * Test for the loadContentDrafts() method.
2368
     *
2369
     * @see \eZ\Publish\API\Repository\ContentService::loadContentDrafts()
2370
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentDraft
2371
     */
2372
    public function testLoadContentDrafts()
2373
    {
2374
        $repository = $this->getRepository();
2375
2376
        /* BEGIN: Use Case */
2377
        // Remote ids of the "Media" and the "eZ Publish Demo Design ..." page
2378
        // of a eZ Publish demo installation.
2379
        $mediaRemoteId = 'a6e35cbcb7cd6ae4b691f3eee30cd262';
2380
        $demoDesignRemoteId = '8b8b22fe3c6061ed500fbd2b377b885f';
2381
2382
        $contentService = $repository->getContentService();
2383
2384
        // "Media" content object
2385
        $mediaContentInfo = $contentService->loadContentInfoByRemoteId($mediaRemoteId);
2386
2387
        // "eZ Publish Demo Design ..." content object
2388
        $demoDesignContentInfo = $contentService->loadContentInfoByRemoteId($demoDesignRemoteId);
2389
2390
        // Create some drafts
2391
        $contentService->createContentDraft($mediaContentInfo);
2392
        $contentService->createContentDraft($demoDesignContentInfo);
2393
2394
        // Now $contentDrafts should contain two drafted versions
2395
        $draftedVersions = $contentService->loadContentDrafts();
2396
        /* END: Use Case */
2397
2398
        $actual = [
2399
            $draftedVersions[0]->status,
2400
            $draftedVersions[0]->getContentInfo()->remoteId,
2401
            $draftedVersions[1]->status,
2402
            $draftedVersions[1]->getContentInfo()->remoteId,
2403
        ];
2404
        sort($actual, SORT_STRING);
2405
2406
        $this->assertEquals(
2407
            [
2408
                VersionInfo::STATUS_DRAFT,
2409
                VersionInfo::STATUS_DRAFT,
2410
                $demoDesignRemoteId,
2411
                $mediaRemoteId,
2412
            ],
2413
            $actual
2414
        );
2415
    }
2416
2417
    /**
2418
     * Test for the loadContentDrafts() method.
2419
     *
2420
     * @see \eZ\Publish\API\Repository\ContentService::loadContentDrafts($user)
2421
     */
2422
    public function testLoadContentDraftsWithFirstParameter()
2423
    {
2424
        $repository = $this->getRepository();
2425
2426
        /* BEGIN: Use Case */
2427
        $user = $this->createUserVersion1();
2428
2429
        // Get current user
2430
        $oldCurrentUser = $repository->getCurrentUser();
2431
2432
        // Set new editor as user
2433
        $repository->setCurrentUser($user);
2434
2435
        // Remote id of the "Media" content object in an eZ Publish demo installation.
2436
        $mediaRemoteId = 'a6e35cbcb7cd6ae4b691f3eee30cd262';
2437
2438
        $contentService = $repository->getContentService();
2439
2440
        // "Media" content object
2441
        $mediaContentInfo = $contentService->loadContentInfoByRemoteId($mediaRemoteId);
2442
2443
        // Create a content draft
2444
        $contentService->createContentDraft($mediaContentInfo);
2445
2446
        // Reset to previous current user
2447
        $repository->setCurrentUser($oldCurrentUser);
2448
2449
        // Now $contentDrafts for the previous current user and the new user
2450
        $newCurrentUserDrafts = $contentService->loadContentDrafts($user);
2451
        $oldCurrentUserDrafts = $contentService->loadContentDrafts($oldCurrentUser);
2452
        /* END: Use Case */
2453
2454
        $this->assertSame([], $oldCurrentUserDrafts);
2455
2456
        $this->assertEquals(
2457
            [
2458
                VersionInfo::STATUS_DRAFT,
2459
                $mediaRemoteId,
2460
            ],
2461
            [
2462
                $newCurrentUserDrafts[0]->status,
2463
                $newCurrentUserDrafts[0]->getContentInfo()->remoteId,
2464
            ]
2465
        );
2466
        $this->assertTrue($newCurrentUserDrafts[0]->isDraft());
2467
        $this->assertFalse($newCurrentUserDrafts[0]->isArchived());
2468
        $this->assertFalse($newCurrentUserDrafts[0]->isPublished());
2469
    }
2470
2471
    /**
2472
     * Test for the loadVersionInfo() method.
2473
     *
2474
     * @see \eZ\Publish\API\Repository\ContentService::loadVersionInfo($contentInfo, $versionNo)
2475
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersionFromContentDraft
2476
     */
2477
    public function testLoadVersionInfoWithSecondParameter()
2478
    {
2479
        $repository = $this->getRepository();
2480
2481
        $contentService = $repository->getContentService();
2482
2483
        /* BEGIN: Use Case */
2484
        $publishedContent = $this->createContentVersion1();
2485
2486
        $draftContent = $contentService->createContentDraft($publishedContent->contentInfo);
2487
2488
        // Will return the VersionInfo of the $draftContent
2489
        $versionInfo = $contentService->loadVersionInfoById($publishedContent->id, 2);
2490
        /* END: Use Case */
2491
2492
        $this->assertEquals(2, $versionInfo->versionNo);
2493
2494
        // Check that ContentInfo contained in VersionInfo has correct main Location id set
2495
        $this->assertEquals(
2496
            $publishedContent->getVersionInfo()->getContentInfo()->mainLocationId,
2497
            $versionInfo->getContentInfo()->mainLocationId
2498
        );
2499
    }
2500
2501
    /**
2502
     * Test for the loadVersionInfo() method.
2503
     *
2504
     * @see \eZ\Publish\API\Repository\ContentService::loadVersionInfo($contentInfo, $versionNo)
2505
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadVersionInfoWithSecondParameter
2506
     */
2507
    public function testLoadVersionInfoThrowsNotFoundExceptionWithSecondParameter()
2508
    {
2509
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\NotFoundException::class);
2510
2511
        $repository = $this->getRepository();
2512
2513
        $contentService = $repository->getContentService();
2514
2515
        /* BEGIN: Use Case */
2516
        $draft = $this->createContentDraftVersion1();
2517
2518
        // This call will fail with a "NotFoundException", because not versionNo
2519
        // 2 exists for this content object.
2520
        $contentService->loadVersionInfo($draft->contentInfo, 2);
2521
        /* END: Use Case */
2522
    }
2523
2524
    /**
2525
     * Test for the loadVersionInfoById() method.
2526
     *
2527
     * @see \eZ\Publish\API\Repository\ContentService::loadVersionInfoById($contentId, $versionNo)
2528
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadVersionInfoWithSecondParameter
2529
     */
2530
    public function testLoadVersionInfoByIdWithSecondParameter()
2531
    {
2532
        $repository = $this->getRepository();
2533
2534
        $contentService = $repository->getContentService();
2535
2536
        /* BEGIN: Use Case */
2537
        $publishedContent = $this->createContentVersion1();
2538
2539
        $draftContent = $contentService->createContentDraft($publishedContent->contentInfo);
2540
2541
        // Will return the VersionInfo of the $draftContent
2542
        $versionInfo = $contentService->loadVersionInfoById($publishedContent->id, 2);
2543
        /* END: Use Case */
2544
2545
        $this->assertEquals(2, $versionInfo->versionNo);
2546
2547
        // Check that ContentInfo contained in VersionInfo has correct main Location id set
2548
        $this->assertEquals(
2549
            $publishedContent->getVersionInfo()->getContentInfo()->mainLocationId,
2550
            $versionInfo->getContentInfo()->mainLocationId
2551
        );
2552
2553
        return [
2554
            'versionInfo' => $versionInfo,
2555
            'draftContent' => $draftContent,
2556
        ];
2557
    }
2558
2559
    /**
2560
     * Test for the returned value of the loadVersionInfoById() method.
2561
     *
2562
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadVersionInfoByIdWithSecondParameter
2563
     * @covers \eZ\Publish\API\Repository\ContentService::loadVersionInfoById
2564
     *
2565
     * @param array $data
2566
     */
2567
    public function testLoadVersionInfoByIdWithSecondParameterSetsExpectedVersionInfo(array $data)
2568
    {
2569
        /** @var \eZ\Publish\API\Repository\Values\Content\VersionInfo $versionInfo */
2570
        $versionInfo = $data['versionInfo'];
2571
        /** @var \eZ\Publish\API\Repository\Values\Content\Content $draftContent */
2572
        $draftContent = $data['draftContent'];
2573
2574
        $this->assertPropertiesCorrect(
2575
            [
2576
                'names' => [
2577
                    'eng-US' => 'An awesome forum',
2578
                ],
2579
                'contentInfo' => new ContentInfo([
2580
                    'id' => $draftContent->contentInfo->id,
2581
                    'contentTypeId' => 28,
2582
                    'name' => 'An awesome forum',
2583
                    'sectionId' => 1,
2584
                    'currentVersionNo' => 1,
2585
                    'published' => true,
2586
                    'ownerId' => 14,
2587
                    // this Content Object is created at the test runtime
2588
                    'modificationDate' => $versionInfo->contentInfo->modificationDate,
2589
                    'publishedDate' => $versionInfo->contentInfo->publishedDate,
2590
                    'alwaysAvailable' => 1,
2591
                    'remoteId' => 'abcdef0123456789abcdef0123456789',
2592
                    'mainLanguageCode' => 'eng-US',
2593
                    'mainLocationId' => $draftContent->contentInfo->mainLocationId,
2594
                    'status' => ContentInfo::STATUS_PUBLISHED,
2595
                ]),
2596
                'id' => $draftContent->versionInfo->id,
2597
                'versionNo' => 2,
2598
                'creatorId' => 14,
2599
                'status' => 0,
2600
                'initialLanguageCode' => 'eng-US',
2601
                'languageCodes' => [
2602
                    'eng-US',
2603
                ],
2604
            ],
2605
            $versionInfo
2606
        );
2607
    }
2608
2609
    /**
2610
     * Test for the loadVersionInfoById() method.
2611
     *
2612
     * @see \eZ\Publish\API\Repository\ContentService::loadVersionInfoById($contentId, $versionNo)
2613
     */
2614
    public function testLoadVersionInfoByIdThrowsNotFoundExceptionWithSecondParameter()
2615
    {
2616
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\NotFoundException::class);
2617
2618
        $repository = $this->getRepository();
2619
2620
        $contentService = $repository->getContentService();
2621
2622
        /* BEGIN: Use Case */
2623
        $content = $this->createContentVersion1();
2624
2625
        // This call will fail with a "NotFoundException", because not versionNo
2626
        // 2 exists for this content object.
2627
        $contentService->loadVersionInfoById($content->id, 2);
2628
        /* END: Use Case */
2629
    }
2630
2631
    /**
2632
     * Test for the loadContentByVersionInfo() method.
2633
     *
2634
     * @see \eZ\Publish\API\Repository\ContentService::loadContentByVersionInfo($versionInfo, $languages)
2635
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContent
2636
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentByVersionInfo
2637
     */
2638
    public function testLoadContentByVersionInfoWithSecondParameter()
2639
    {
2640
        $repository = $this->getRepository();
2641
2642
        $sectionId = $this->generateId('section', 1);
2643
        /* BEGIN: Use Case */
2644
        $contentTypeService = $repository->getContentTypeService();
2645
2646
        $contentType = $contentTypeService->loadContentTypeByIdentifier('forum');
2647
2648
        $contentService = $repository->getContentService();
2649
2650
        $contentCreateStruct = $contentService->newContentCreateStruct($contentType, 'eng-US');
2651
2652
        $contentCreateStruct->setField('name', 'Sindelfingen forum²');
2653
2654
        $contentCreateStruct->setField('name', 'Sindelfingen forum²³', 'eng-GB');
2655
2656
        $contentCreateStruct->remoteId = 'abcdef0123456789abcdef0123456789';
2657
        // $sectionId contains the ID of section 1
2658
        $contentCreateStruct->sectionId = $sectionId;
2659
        $contentCreateStruct->alwaysAvailable = true;
2660
2661
        // Create a new content draft
2662
        $content = $contentService->createContent($contentCreateStruct);
2663
2664
        // Now publish this draft
2665
        $publishedContent = $contentService->publishVersion($content->getVersionInfo());
2666
2667
        // Will return a content instance with fields in "eng-US"
2668
        $reloadedContent = $contentService->loadContentByVersionInfo(
2669
            $publishedContent->getVersionInfo(),
2670
            [
2671
                'eng-GB',
2672
            ],
2673
            false
2674
        );
2675
        /* END: Use Case */
2676
2677
        $actual = [];
2678
        foreach ($reloadedContent->getFields() as $field) {
2679
            $actual[] = new Field(
2680
                [
2681
                    'id' => 0,
2682
                    'value' => ($field->value !== null ? true : null), // Actual value tested by FieldType integration tests
2683
                    'languageCode' => $field->languageCode,
2684
                    'fieldDefIdentifier' => $field->fieldDefIdentifier,
2685
                ]
2686
            );
2687
        }
2688
        usort(
2689
            $actual,
2690
            function ($field1, $field2) {
2691
                if (0 === ($return = strcasecmp($field1->fieldDefIdentifier, $field2->fieldDefIdentifier))) {
2692
                    return strcasecmp($field1->languageCode, $field2->languageCode);
2693
                }
2694
2695
                return $return;
2696
            }
2697
        );
2698
2699
        $expected = [
2700
            new Field(
2701
                [
2702
                    'id' => 0,
2703
                    'value' => true,
2704
                    'languageCode' => 'eng-GB',
2705
                    'fieldDefIdentifier' => 'description',
2706
                ]
2707
            ),
2708
            new Field(
2709
                [
2710
                    'id' => 0,
2711
                    'value' => true,
2712
                    'languageCode' => 'eng-GB',
2713
                    'fieldDefIdentifier' => 'name',
2714
                ]
2715
            ),
2716
        ];
2717
2718
        $this->assertEquals($expected, $actual);
2719
    }
2720
2721
    /**
2722
     * Test for the loadContentByContentInfo() method.
2723
     *
2724
     * @see \eZ\Publish\API\Repository\ContentService::loadContentByContentInfo($contentInfo, $languages)
2725
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentByContentInfo
2726
     */
2727
    public function testLoadContentByContentInfoWithLanguageParameters()
2728
    {
2729
        $repository = $this->getRepository();
2730
2731
        $sectionId = $this->generateId('section', 1);
2732
        /* BEGIN: Use Case */
2733
        $contentTypeService = $repository->getContentTypeService();
2734
2735
        $contentType = $contentTypeService->loadContentTypeByIdentifier('forum');
2736
2737
        $contentService = $repository->getContentService();
2738
2739
        $contentCreateStruct = $contentService->newContentCreateStruct($contentType, 'eng-US');
2740
2741
        $contentCreateStruct->setField('name', 'Sindelfingen forum²');
2742
2743
        $contentCreateStruct->setField('name', 'Sindelfingen forum²³', 'eng-GB');
2744
2745
        $contentCreateStruct->remoteId = 'abcdef0123456789abcdef0123456789';
2746
        // $sectionId contains the ID of section 1
2747
        $contentCreateStruct->sectionId = $sectionId;
2748
        $contentCreateStruct->alwaysAvailable = true;
2749
2750
        // Create a new content draft
2751
        $content = $contentService->createContent($contentCreateStruct);
2752
2753
        // Now publish this draft
2754
        $publishedContent = $contentService->publishVersion($content->getVersionInfo());
2755
2756
        // Will return a content instance with fields in "eng-US"
2757
        $reloadedContent = $contentService->loadContentByContentInfo(
2758
            $publishedContent->contentInfo,
2759
            [
2760
                'eng-US',
2761
            ],
2762
            null,
2763
            false
2764
        );
2765
        /* END: Use Case */
2766
2767
        $actual = $this->normalizeFields($reloadedContent->getFields());
2768
2769
        $expected = [
2770
            new Field(
2771
                [
2772
                    'id' => 0,
2773
                    'value' => true,
2774
                    'languageCode' => 'eng-US',
2775
                    'fieldDefIdentifier' => 'description',
2776
                    'fieldTypeIdentifier' => 'ezrichtext',
2777
                ]
2778
            ),
2779
            new Field(
2780
                [
2781
                    'id' => 0,
2782
                    'value' => true,
2783
                    'languageCode' => 'eng-US',
2784
                    'fieldDefIdentifier' => 'name',
2785
                    'fieldTypeIdentifier' => 'ezstring',
2786
                ]
2787
            ),
2788
        ];
2789
2790
        $this->assertEquals($expected, $actual);
2791
2792
        // Will return a content instance with fields in "eng-GB" (versions prior to 6.0.0-beta9 returned "eng-US" also)
2793
        $reloadedContent = $contentService->loadContentByContentInfo(
2794
            $publishedContent->contentInfo,
2795
            [
2796
                'eng-GB',
2797
            ],
2798
            null,
2799
            true
2800
        );
2801
2802
        $actual = $this->normalizeFields($reloadedContent->getFields());
2803
2804
        $expected = [
2805
            new Field(
2806
                [
2807
                    'id' => 0,
2808
                    'value' => true,
2809
                    'languageCode' => 'eng-GB',
2810
                    'fieldDefIdentifier' => 'description',
2811
                    'fieldTypeIdentifier' => 'ezrichtext',
2812
                ]
2813
            ),
2814
            new Field(
2815
                [
2816
                    'id' => 0,
2817
                    'value' => true,
2818
                    'languageCode' => 'eng-GB',
2819
                    'fieldDefIdentifier' => 'name',
2820
                    'fieldTypeIdentifier' => 'ezstring',
2821
                ]
2822
            ),
2823
        ];
2824
2825
        $this->assertEquals($expected, $actual);
2826
2827
        // Will return a content instance with fields in main language "eng-US", as "fre-FR" does not exists
2828
        $reloadedContent = $contentService->loadContentByContentInfo(
2829
            $publishedContent->contentInfo,
2830
            [
2831
                'fre-FR',
2832
            ],
2833
            null,
2834
            true
2835
        );
2836
2837
        $actual = $this->normalizeFields($reloadedContent->getFields());
2838
2839
        $expected = [
2840
            new Field(
2841
                [
2842
                    'id' => 0,
2843
                    'value' => true,
2844
                    'languageCode' => 'eng-US',
2845
                    'fieldDefIdentifier' => 'description',
2846
                    'fieldTypeIdentifier' => 'ezrichtext',
2847
                ]
2848
            ),
2849
            new Field(
2850
                [
2851
                    'id' => 0,
2852
                    'value' => true,
2853
                    'languageCode' => 'eng-US',
2854
                    'fieldDefIdentifier' => 'name',
2855
                    'fieldTypeIdentifier' => 'ezstring',
2856
                ]
2857
            ),
2858
        ];
2859
2860
        $this->assertEquals($expected, $actual);
2861
    }
2862
2863
    /**
2864
     * Test for the loadContentByContentInfo() method.
2865
     *
2866
     * @see \eZ\Publish\API\Repository\ContentService::loadContentByContentInfo($contentInfo, $languages, $versionNo)
2867
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentByContentInfo
2868
     */
2869
    public function testLoadContentByContentInfoWithVersionNumberParameter()
2870
    {
2871
        $repository = $this->getRepository();
2872
2873
        $contentService = $repository->getContentService();
2874
2875
        /* BEGIN: Use Case */
2876
        $publishedContent = $this->createContentVersion1();
2877
2878
        $draftContent = $contentService->createContentDraft($publishedContent->contentInfo);
2879
2880
        // This content instance is identical to $draftContent
2881
        $draftContentReloaded = $contentService->loadContentByContentInfo(
2882
            $publishedContent->contentInfo,
2883
            null,
2884
            2
2885
        );
2886
        /* END: Use Case */
2887
2888
        $this->assertEquals(
2889
            2,
2890
            $draftContentReloaded->getVersionInfo()->versionNo
2891
        );
2892
2893
        // Check that ContentInfo contained in reloaded draft Content has correct main Location id set
2894
        $this->assertEquals(
2895
            $publishedContent->versionInfo->contentInfo->mainLocationId,
2896
            $draftContentReloaded->versionInfo->contentInfo->mainLocationId
2897
        );
2898
    }
2899
2900
    /**
2901
     * Test for the loadContentByContentInfo() method.
2902
     *
2903
     * @see \eZ\Publish\API\Repository\ContentService::loadContentByContentInfo($contentInfo, $languages, $versionNo)
2904
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentByContentInfoWithVersionNumberParameter
2905
     */
2906
    public function testLoadContentByContentInfoThrowsNotFoundExceptionWithVersionNumberParameter()
2907
    {
2908
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\NotFoundException::class);
2909
2910
        $repository = $this->getRepository();
2911
2912
        $contentService = $repository->getContentService();
2913
2914
        /* BEGIN: Use Case */
2915
        $content = $this->createContentVersion1();
2916
2917
        // This call will fail with a "NotFoundException", because no content
2918
        // with versionNo = 2 exists.
2919
        $contentService->loadContentByContentInfo($content->contentInfo, null, 2);
2920
        /* END: Use Case */
2921
    }
2922
2923
    /**
2924
     * Test for the loadContent() method.
2925
     *
2926
     * @see \eZ\Publish\API\Repository\ContentService::loadContent($contentId, $languages)
2927
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersionFromContentDraft
2928
     */
2929
    public function testLoadContentWithSecondParameter()
2930
    {
2931
        $repository = $this->getRepository();
2932
2933
        $contentService = $repository->getContentService();
2934
2935
        /* BEGIN: Use Case */
2936
        $draft = $this->createMultipleLanguageDraftVersion1();
2937
2938
        // This draft contains those fields localized with "eng-GB"
2939
        $draftLocalized = $contentService->loadContent($draft->id, ['eng-GB'], null, false);
2940
        /* END: Use Case */
2941
2942
        $this->assertLocaleFieldsEquals($draftLocalized->getFields(), 'eng-GB');
2943
2944
        return $draft;
2945
    }
2946
2947
    /**
2948
     * Test for the loadContent() method using undefined translation.
2949
     *
2950
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentWithSecondParameter
2951
     *
2952
     * @param \eZ\Publish\API\Repository\Values\Content\Content $contentDraft
2953
     */
2954
    public function testLoadContentWithSecondParameterThrowsNotFoundException(Content $contentDraft)
2955
    {
2956
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\NotFoundException::class);
2957
2958
        $repository = $this->getRepository();
2959
2960
        $contentService = $repository->getContentService();
2961
2962
        $contentService->loadContent($contentDraft->id, ['ger-DE'], null, false);
2963
    }
2964
2965
    /**
2966
     * Test for the loadContent() method.
2967
     *
2968
     * @see \eZ\Publish\API\Repository\ContentService::loadContent($contentId, $languages, $versionNo)
2969
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersionFromContentDraft
2970
     */
2971
    public function testLoadContentWithThirdParameter()
2972
    {
2973
        $repository = $this->getRepository();
2974
2975
        $contentService = $repository->getContentService();
2976
2977
        /* BEGIN: Use Case */
2978
        $publishedContent = $this->createContentVersion1();
2979
2980
        $draftContent = $contentService->createContentDraft($publishedContent->contentInfo);
2981
2982
        // This content instance is identical to $draftContent
2983
        $draftContentReloaded = $contentService->loadContent($publishedContent->id, null, 2);
2984
        /* END: Use Case */
2985
2986
        $this->assertEquals(2, $draftContentReloaded->getVersionInfo()->versionNo);
2987
2988
        // Check that ContentInfo contained in reloaded draft Content has correct main Location id set
2989
        $this->assertEquals(
2990
            $publishedContent->versionInfo->contentInfo->mainLocationId,
2991
            $draftContentReloaded->versionInfo->contentInfo->mainLocationId
2992
        );
2993
    }
2994
2995
    /**
2996
     * Test for the loadContent() method.
2997
     *
2998
     * @see \eZ\Publish\API\Repository\ContentService::loadContent($contentId, $languages, $versionNo)
2999
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentWithThirdParameter
3000
     */
3001
    public function testLoadContentThrowsNotFoundExceptionWithThirdParameter()
3002
    {
3003
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\NotFoundException::class);
3004
3005
        $repository = $this->getRepository();
3006
3007
        $contentService = $repository->getContentService();
3008
3009
        /* BEGIN: Use Case */
3010
        $content = $this->createContentVersion1();
3011
3012
        // This call will fail with a "NotFoundException", because for this
3013
        // content object no versionNo=2 exists.
3014
        $contentService->loadContent($content->id, null, 2);
3015
        /* END: Use Case */
3016
    }
3017
3018
    /**
3019
     * Test for the loadContentByRemoteId() method.
3020
     *
3021
     * @see \eZ\Publish\API\Repository\ContentService::loadContentByRemoteId($remoteId, $languages)
3022
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersionFromContentDraft
3023
     */
3024
    public function testLoadContentByRemoteIdWithSecondParameter()
3025
    {
3026
        $repository = $this->getRepository();
3027
3028
        $contentService = $repository->getContentService();
3029
3030
        /* BEGIN: Use Case */
3031
        $draft = $this->createMultipleLanguageDraftVersion1();
3032
3033
        $contentService->publishVersion($draft->versionInfo);
3034
3035
        // This draft contains those fields localized with "eng-GB"
3036
        $draftLocalized = $contentService->loadContentByRemoteId(
3037
            $draft->contentInfo->remoteId,
3038
            ['eng-GB'],
3039
            null,
3040
            false
3041
        );
3042
        /* END: Use Case */
3043
3044
        $this->assertLocaleFieldsEquals($draftLocalized->getFields(), 'eng-GB');
3045
    }
3046
3047
    /**
3048
     * Test for the loadContentByRemoteId() method.
3049
     *
3050
     * @see \eZ\Publish\API\Repository\ContentService::loadContentByRemoteId($remoteId, $languages, $versionNo)
3051
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersionFromContentDraft
3052
     */
3053
    public function testLoadContentByRemoteIdWithThirdParameter()
3054
    {
3055
        $repository = $this->getRepository();
3056
3057
        $contentService = $repository->getContentService();
3058
3059
        /* BEGIN: Use Case */
3060
        $publishedContent = $this->createContentVersion1();
3061
3062
        $draftContent = $contentService->createContentDraft($publishedContent->contentInfo);
3063
3064
        // This content instance is identical to $draftContent
3065
        $draftContentReloaded = $contentService->loadContentByRemoteId(
3066
            $publishedContent->contentInfo->remoteId,
3067
            null,
3068
            2
3069
        );
3070
        /* END: Use Case */
3071
3072
        $this->assertEquals(2, $draftContentReloaded->getVersionInfo()->versionNo);
3073
3074
        // Check that ContentInfo contained in reloaded draft Content has correct main Location id set
3075
        $this->assertEquals(
3076
            $publishedContent->versionInfo->contentInfo->mainLocationId,
3077
            $draftContentReloaded->versionInfo->contentInfo->mainLocationId
3078
        );
3079
    }
3080
3081
    /**
3082
     * Test for the loadContentByRemoteId() method.
3083
     *
3084
     * @see \eZ\Publish\API\Repository\ContentService::loadContentByRemoteId($remoteId, $languages, $versionNo)
3085
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentByRemoteIdWithThirdParameter
3086
     */
3087
    public function testLoadContentByRemoteIdThrowsNotFoundExceptionWithThirdParameter()
3088
    {
3089
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\NotFoundException::class);
3090
3091
        $repository = $this->getRepository();
3092
3093
        $contentService = $repository->getContentService();
3094
3095
        /* BEGIN: Use Case */
3096
        $content = $this->createContentVersion1();
3097
3098
        // This call will fail with a "NotFoundException", because for this
3099
        // content object no versionNo=2 exists.
3100
        $contentService->loadContentByRemoteId(
3101
            $content->contentInfo->remoteId,
3102
            null,
3103
            2
3104
        );
3105
        /* END: Use Case */
3106
    }
3107
3108
    /**
3109
     * Test that retrieval of translated name field respects prioritized language list.
3110
     *
3111
     * @dataProvider getPrioritizedLanguageList
3112
     * @param string[]|null $languageCodes
3113
     */
3114
    public function testLoadContentWithPrioritizedLanguagesList($languageCodes)
3115
    {
3116
        $repository = $this->getRepository();
3117
3118
        $contentService = $repository->getContentService();
3119
3120
        $content = $this->createContentVersion2();
3121
3122
        $content = $contentService->loadContent($content->id, $languageCodes);
3123
3124
        $expectedName = $content->getVersionInfo()->getName(
3125
            isset($languageCodes[0]) ? $languageCodes[0] : null
3126
        );
3127
        $nameValue = $content->getFieldValue('name');
3128
        /** @var \eZ\Publish\Core\FieldType\TextLine\Value $nameValue */
3129
        self::assertEquals($expectedName, $nameValue->text);
3130
        self::assertEquals($expectedName, $content->getVersionInfo()->getName());
3131
        // Also check value on shortcut method on content
3132
        self::assertEquals($expectedName, $content->getName());
3133
    }
3134
3135
    /**
3136
     * @return array
3137
     */
3138
    public function getPrioritizedLanguageList()
3139
    {
3140
        return [
3141
            [['eng-US']],
3142
            [['eng-GB']],
3143
            [['eng-GB', 'eng-US']],
3144
            [['eng-US', 'eng-GB']],
3145
        ];
3146
    }
3147
3148
    /**
3149
     * Test for the deleteVersion() method.
3150
     *
3151
     * @see \eZ\Publish\API\Repository\ContentService::deleteVersion()
3152
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContent
3153
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContent
3154
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersion
3155
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentDraft
3156
     */
3157
    public function testDeleteVersion()
3158
    {
3159
        $repository = $this->getRepository();
3160
3161
        $contentService = $repository->getContentService();
3162
3163
        /* BEGIN: Use Case */
3164
        $content = $this->createContentVersion1();
3165
3166
        // Create new draft, because published or last version of the Content can't be deleted
3167
        $draft = $contentService->createContentDraft(
3168
            $content->getVersionInfo()->getContentInfo()
3169
        );
3170
3171
        // Delete the previously created draft
3172
        $contentService->deleteVersion($draft->getVersionInfo());
3173
        /* END: Use Case */
3174
3175
        $versions = $contentService->loadVersions($content->getVersionInfo()->getContentInfo());
3176
3177
        $this->assertCount(1, $versions);
3178
        $this->assertEquals(
3179
            $content->getVersionInfo()->id,
3180
            $versions[0]->id
3181
        );
3182
    }
3183
3184
    /**
3185
     * Test for the deleteVersion() method.
3186
     *
3187
     * @see \eZ\Publish\API\Repository\ContentService::deleteVersion()
3188
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContent
3189
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContent
3190
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersion
3191
     */
3192
    public function testDeleteVersionThrowsBadStateExceptionOnPublishedVersion()
3193
    {
3194
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\BadStateException::class);
3195
3196
        $repository = $this->getRepository();
3197
3198
        $contentService = $repository->getContentService();
3199
3200
        /* BEGIN: Use Case */
3201
        $content = $this->createContentVersion1();
3202
3203
        // This call will fail with a "BadStateException", because the content
3204
        // version is currently published.
3205
        $contentService->deleteVersion($content->getVersionInfo());
3206
        /* END: Use Case */
3207
    }
3208
3209
    /**
3210
     * Test for the deleteVersion() method.
3211
     *
3212
     * @see \eZ\Publish\API\Repository\ContentService::deleteVersion()
3213
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContent
3214
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContent
3215
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersion
3216
     */
3217
    public function testDeleteVersionWorksIfOnlyVersionIsDraft()
3218
    {
3219
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\NotFoundException::class);
3220
3221
        $repository = $this->getRepository();
3222
3223
        $contentService = $repository->getContentService();
3224
3225
        /* BEGIN: Use Case */
3226
        $draft = $this->createContentDraftVersion1();
3227
3228
        $contentService->deleteVersion($draft->getVersionInfo());
3229
3230
        // This call will fail with a "NotFound", because we allow to delete content if remaining version is draft.
3231
        // Can normally only happen if there where always only a draft to begin with, simplifies UI edit API usage.
3232
        $contentService->loadContent($draft->id);
3233
        /* END: Use Case */
3234
    }
3235
3236
    /**
3237
     * Test for the loadVersions() method.
3238
     *
3239
     * @see \eZ\Publish\API\Repository\ContentService::loadVersions()
3240
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersion
3241
     *
3242
     * @return \eZ\Publish\API\Repository\Values\Content\VersionInfo[]
3243
     */
3244
    public function testLoadVersions()
3245
    {
3246
        $repository = $this->getRepository();
3247
3248
        $contentService = $repository->getContentService();
3249
3250
        /* BEGIN: Use Case */
3251
        $contentVersion2 = $this->createContentVersion2();
3252
3253
        // Load versions of this ContentInfo instance
3254
        $versions = $contentService->loadVersions($contentVersion2->contentInfo);
3255
        /* END: Use Case */
3256
3257
        $expectedVersionsOrder = [
3258
            $contentService->loadVersionInfo($contentVersion2->contentInfo, 1),
3259
            $contentService->loadVersionInfo($contentVersion2->contentInfo, 2),
3260
        ];
3261
3262
        $this->assertEquals($expectedVersionsOrder, $versions);
3263
3264
        return $versions;
3265
    }
3266
3267
    /**
3268
     * Test for the loadVersions() method.
3269
     *
3270
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadVersions
3271
     * @covers \eZ\Publish\Core\Repository\ContentService::loadVersions
3272
     *
3273
     * @param \eZ\Publish\API\Repository\Values\Content\VersionInfo[] $versions
3274
     */
3275
    public function testLoadVersionsSetsExpectedVersionInfo(array $versions)
3276
    {
3277
        $this->assertCount(2, $versions);
3278
3279
        $expectedVersions = [
3280
            [
3281
                'versionNo' => 1,
3282
                'creatorId' => 14,
3283
                'status' => VersionInfo::STATUS_ARCHIVED,
3284
                'initialLanguageCode' => 'eng-US',
3285
                'languageCodes' => ['eng-US'],
3286
            ],
3287
            [
3288
                'versionNo' => 2,
3289
                'creatorId' => 10,
3290
                'status' => VersionInfo::STATUS_PUBLISHED,
3291
                'initialLanguageCode' => 'eng-US',
3292
                'languageCodes' => ['eng-US', 'eng-GB'],
3293
            ],
3294
        ];
3295
3296
        $this->assertPropertiesCorrect($expectedVersions[0], $versions[0]);
3297
        $this->assertPropertiesCorrect($expectedVersions[1], $versions[1]);
3298
        $this->assertEqualsWithDelta(
3299
            $versions[0]->creationDate->getTimestamp(),
3300
            $versions[1]->creationDate->getTimestamp(),
3301
            2,
3302
            'Creation time did not match within delta of 2 seconds',
3303
        );
0 ignored issues
show
Bug introduced by
This code did not parse for me. Apparently, there is an error somewhere around this line:

Syntax error, unexpected ')'
Loading history...
3304
        $this->assertEqualsWithDelta(
3305
            $versions[0]->modificationDate->getTimestamp(),
3306
            $versions[1]->modificationDate->getTimestamp(),
3307
            2,
3308
            'Creation time did not match within delta of 2 seconds',
3309
        );
3310
        $this->assertTrue($versions[0]->isArchived());
3311
        $this->assertFalse($versions[0]->isDraft());
3312
        $this->assertFalse($versions[0]->isPublished());
3313
3314
        $this->assertTrue($versions[1]->isPublished());
3315
        $this->assertFalse($versions[1]->isDraft());
3316
        $this->assertFalse($versions[1]->isArchived());
3317
    }
3318
3319
    /**
3320
     * Test for the copyContent() method.
3321
     *
3322
     * @see \eZ\Publish\API\Repository\ContentService::copyContent()
3323
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersionFromContentDraft
3324
     * @group field-type
3325
     */
3326
    public function testCopyContent()
3327
    {
3328
        $parentLocationId = $this->generateId('location', 56);
3329
3330
        $repository = $this->getRepository();
3331
3332
        $contentService = $repository->getContentService();
3333
        $locationService = $repository->getLocationService();
3334
3335
        /* BEGIN: Use Case */
3336
        $contentVersion2 = $this->createMultipleLanguageContentVersion2();
3337
3338
        // Configure new target location
3339
        $targetLocationCreate = $locationService->newLocationCreateStruct($parentLocationId);
3340
3341
        $targetLocationCreate->priority = 42;
3342
        $targetLocationCreate->hidden = true;
3343
        $targetLocationCreate->remoteId = '01234abcdef5678901234abcdef56789';
3344
        $targetLocationCreate->sortField = Location::SORT_FIELD_NODE_ID;
3345
        $targetLocationCreate->sortOrder = Location::SORT_ORDER_DESC;
3346
3347
        // Copy content with all versions and drafts
3348
        $contentCopied = $contentService->copyContent(
3349
            $contentVersion2->contentInfo,
3350
            $targetLocationCreate
3351
        );
3352
        /* END: Use Case */
3353
3354
        $this->assertInstanceOf(
3355
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\Content',
3356
            $contentCopied
3357
        );
3358
3359
        $this->assertNotEquals(
3360
            $contentVersion2->contentInfo->remoteId,
3361
            $contentCopied->contentInfo->remoteId
3362
        );
3363
3364
        $this->assertNotEquals(
3365
            $contentVersion2->id,
3366
            $contentCopied->id
3367
        );
3368
3369
        $this->assertCount(
3370
            2,
3371
            $contentService->loadVersions($contentCopied->contentInfo)
3372
        );
3373
3374
        $this->assertEquals(2, $contentCopied->getVersionInfo()->versionNo);
3375
3376
        $this->assertAllFieldsEquals($contentCopied->getFields());
3377
3378
        $this->assertDefaultContentStates($contentCopied->contentInfo);
3379
3380
        $this->assertNotNull(
3381
            $contentCopied->contentInfo->mainLocationId,
3382
            'Expected main location to be set given we provided a LocationCreateStruct'
3383
        );
3384
    }
3385
3386
    /**
3387
     * Test for the copyContent() method with ezsettings.default.content.retain_owner_on_copy set to false
3388
     * See settings/test/integration_legacy.yml for service override.
3389
     *
3390
     * @see \eZ\Publish\API\Repository\ContentService::copyContent()
3391
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersionFromContentDraft
3392
     * @group field-type
3393
     */
3394
    public function testCopyContentWithNewOwner()
3395
    {
3396
        $parentLocationId = $this->generateId('location', 56);
3397
3398
        $repository = $this->getRepository();
3399
3400
        $contentService = $repository->getContentService();
3401
        $locationService = $repository->getLocationService();
3402
        $userService = $repository->getUserService();
3403
3404
        $newOwner = $this->createUser('new_owner', 'foo', 'bar');
3405
        /* BEGIN: Use Case */
3406
        /** @var \eZ\Publish\API\Repository\Values\Content\Content $contentVersion2 */
3407
        $contentVersion2 = $this->createContentDraftVersion1(
3408
            $parentLocationId,
3409
            'forum',
3410
            'name',
3411
            $newOwner
3412
        );
3413
3414
        // Configure new target location
3415
        $targetLocationCreate = $locationService->newLocationCreateStruct($parentLocationId);
3416
3417
        $targetLocationCreate->priority = 42;
3418
        $targetLocationCreate->hidden = true;
3419
        $targetLocationCreate->remoteId = '01234abcdef5678901234abcdef56789';
3420
        $targetLocationCreate->sortField = Location::SORT_FIELD_NODE_ID;
3421
        $targetLocationCreate->sortOrder = Location::SORT_ORDER_DESC;
3422
3423
        // Copy content with all versions and drafts
3424
        $contentCopied = $contentService->copyContent(
3425
            $contentVersion2->contentInfo,
3426
            $targetLocationCreate
3427
        );
3428
        /* END: Use Case */
3429
3430
        $this->assertEquals(
3431
            $newOwner->id,
3432
            $contentVersion2->contentInfo->ownerId
3433
        );
3434
        $this->assertEquals(
3435
            $userService->loadUserByLogin('admin')->getUserId(),
3436
            $contentCopied->contentInfo->ownerId
3437
        );
3438
    }
3439
3440
    /**
3441
     * Test for the copyContent() method.
3442
     *
3443
     * @see \eZ\Publish\API\Repository\ContentService::copyContent($contentInfo, $destinationLocationCreateStruct, $versionInfo)
3444
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCopyContent
3445
     *
3446
     * @todo Fix to more descriptive name
3447
     */
3448
    public function testCopyContentWithThirdParameter()
3449
    {
3450
        $parentLocationId = $this->generateId('location', 56);
3451
3452
        $repository = $this->getRepository();
3453
3454
        $contentService = $repository->getContentService();
3455
        $locationService = $repository->getLocationService();
3456
3457
        /* BEGIN: Use Case */
3458
        $contentVersion2 = $this->createContentVersion2();
3459
3460
        // Configure new target location
3461
        $targetLocationCreate = $locationService->newLocationCreateStruct($parentLocationId);
3462
3463
        $targetLocationCreate->priority = 42;
3464
        $targetLocationCreate->hidden = true;
3465
        $targetLocationCreate->remoteId = '01234abcdef5678901234abcdef56789';
3466
        $targetLocationCreate->sortField = Location::SORT_FIELD_NODE_ID;
3467
        $targetLocationCreate->sortOrder = Location::SORT_ORDER_DESC;
3468
3469
        // Copy only the initial version
3470
        $contentCopied = $contentService->copyContent(
3471
            $contentVersion2->contentInfo,
3472
            $targetLocationCreate,
3473
            $contentService->loadVersionInfo($contentVersion2->contentInfo, 1)
3474
        );
3475
        /* END: Use Case */
3476
3477
        $this->assertInstanceOf(
3478
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\Content',
3479
            $contentCopied
3480
        );
3481
3482
        $this->assertNotEquals(
3483
            $contentVersion2->contentInfo->remoteId,
3484
            $contentCopied->contentInfo->remoteId
3485
        );
3486
3487
        $this->assertNotEquals(
3488
            $contentVersion2->id,
3489
            $contentCopied->id
3490
        );
3491
3492
        $this->assertCount(
3493
            1,
3494
            $contentService->loadVersions($contentCopied->contentInfo)
3495
        );
3496
3497
        $this->assertEquals(1, $contentCopied->getVersionInfo()->versionNo);
3498
3499
        $this->assertNotNull(
3500
            $contentCopied->contentInfo->mainLocationId,
3501
            'Expected main location to be set given we provided a LocationCreateStruct'
3502
        );
3503
    }
3504
3505
    /**
3506
     * Test for the addRelation() method.
3507
     *
3508
     * @return \eZ\Publish\API\Repository\Values\Content\Content
3509
     *
3510
     * @see \eZ\Publish\API\Repository\ContentService::addRelation()
3511
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersionFromContentDraft
3512
     */
3513
    public function testAddRelation()
3514
    {
3515
        $repository = $this->getRepository();
3516
3517
        $contentService = $repository->getContentService();
3518
3519
        /* BEGIN: Use Case */
3520
        // RemoteId of the "Media" content of an eZ Publish demo installation
3521
        $mediaRemoteId = 'a6e35cbcb7cd6ae4b691f3eee30cd262';
3522
3523
        $draft = $this->createContentDraftVersion1();
3524
3525
        $media = $contentService->loadContentInfoByRemoteId($mediaRemoteId);
3526
3527
        // Create relation between new content object and "Media" page
3528
        $relation = $contentService->addRelation(
3529
            $draft->getVersionInfo(),
3530
            $media
3531
        );
3532
        /* END: Use Case */
3533
3534
        $this->assertInstanceOf(
3535
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\Relation',
3536
            $relation
3537
        );
3538
3539
        return $contentService->loadRelations($draft->getVersionInfo());
3540
    }
3541
3542
    /**
3543
     * Test for the addRelation() method.
3544
     *
3545
     * @param \eZ\Publish\API\Repository\Values\Content\Relation[] $relations
3546
     *
3547
     * @see \eZ\Publish\API\Repository\ContentService::addRelation()
3548
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testAddRelation
3549
     */
3550
    public function testAddRelationAddsRelationToContent($relations)
3551
    {
3552
        $this->assertCount(
3553
            1,
3554
            $relations
3555
        );
3556
    }
3557
3558
    /**
3559
     * @param \eZ\Publish\API\Repository\Values\Content\Relation[] $relations
3560
     */
3561
    protected function assertExpectedRelations($relations)
3562
    {
3563
        $this->assertEquals(
3564
            [
3565
                'type' => Relation::COMMON,
3566
                'sourceFieldDefinitionIdentifier' => null,
3567
                'sourceContentInfo' => 'abcdef0123456789abcdef0123456789',
3568
                'destinationContentInfo' => 'a6e35cbcb7cd6ae4b691f3eee30cd262',
3569
            ],
3570
            [
3571
                'type' => $relations[0]->type,
3572
                'sourceFieldDefinitionIdentifier' => $relations[0]->sourceFieldDefinitionIdentifier,
3573
                'sourceContentInfo' => $relations[0]->sourceContentInfo->remoteId,
3574
                'destinationContentInfo' => $relations[0]->destinationContentInfo->remoteId,
3575
            ]
3576
        );
3577
    }
3578
3579
    /**
3580
     * Test for the addRelation() method.
3581
     *
3582
     * @param \eZ\Publish\API\Repository\Values\Content\Relation[] $relations
3583
     *
3584
     * @see \eZ\Publish\API\Repository\ContentService::addRelation()
3585
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testAddRelation
3586
     */
3587
    public function testAddRelationSetsExpectedRelations($relations)
3588
    {
3589
        $this->assertExpectedRelations($relations);
3590
    }
3591
3592
    /**
3593
     * Test for the createContentDraft() method.
3594
     *
3595
     * @return \eZ\Publish\API\Repository\Values\Content\Relation[]
3596
     *
3597
     * @see \eZ\Publish\API\Repository\ContentService::createContentDraft()
3598
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testAddRelationSetsExpectedRelations
3599
     */
3600
    public function testCreateContentDraftWithRelations()
3601
    {
3602
        $repository = $this->getRepository();
3603
3604
        $contentService = $repository->getContentService();
3605
3606
        // RemoteId of the "Media" content of an eZ Publish demo installation
3607
        $mediaRemoteId = 'a6e35cbcb7cd6ae4b691f3eee30cd262';
3608
        $draft = $this->createContentDraftVersion1();
3609
        $media = $contentService->loadContentInfoByRemoteId($mediaRemoteId);
3610
3611
        // Create relation between new content object and "Media" page
3612
        $contentService->addRelation(
3613
            $draft->getVersionInfo(),
3614
            $media
3615
        );
3616
3617
        $content = $contentService->publishVersion($draft->versionInfo);
3618
        $newDraft = $contentService->createContentDraft($content->contentInfo);
3619
3620
        return $contentService->loadRelations($newDraft->getVersionInfo());
3621
    }
3622
3623
    /**
3624
     * Test for the createContentDraft() method.
3625
     *
3626
     * @param \eZ\Publish\API\Repository\Values\Content\Relation[] $relations
3627
     *
3628
     * @return \eZ\Publish\API\Repository\Values\Content\Relation[]
3629
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentDraftWithRelations
3630
     */
3631
    public function testCreateContentDraftWithRelationsCreatesRelations($relations)
3632
    {
3633
        $this->assertCount(
3634
            1,
3635
            $relations
3636
        );
3637
3638
        return $relations;
3639
    }
3640
3641
    /**
3642
     * Test for the createContentDraft() method.
3643
     *
3644
     * @param \eZ\Publish\API\Repository\Values\Content\Relation[] $relations
3645
     *
3646
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentDraftWithRelationsCreatesRelations
3647
     */
3648
    public function testCreateContentDraftWithRelationsCreatesExpectedRelations($relations)
3649
    {
3650
        $this->assertExpectedRelations($relations);
3651
    }
3652
3653
    /**
3654
     * Test for the addRelation() method.
3655
     *
3656
     * @see \eZ\Publish\API\Repository\ContentService::addRelation()
3657
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testAddRelation
3658
     */
3659
    public function testAddRelationThrowsBadStateException()
3660
    {
3661
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\BadStateException::class);
3662
3663
        $repository = $this->getRepository();
3664
3665
        $contentService = $repository->getContentService();
3666
3667
        /* BEGIN: Use Case */
3668
        // RemoteId of the "Media" page of an eZ Publish demo installation
3669
        $mediaRemoteId = 'a6e35cbcb7cd6ae4b691f3eee30cd262';
3670
3671
        $content = $this->createContentVersion1();
3672
3673
        $media = $contentService->loadContentInfoByRemoteId($mediaRemoteId);
3674
3675
        // This call will fail with a "BadStateException", because content is
3676
        // published and not a draft.
3677
        $contentService->addRelation(
3678
            $content->getVersionInfo(),
3679
            $media
3680
        );
3681
        /* END: Use Case */
3682
    }
3683
3684
    /**
3685
     * Test for the loadRelations() method.
3686
     *
3687
     * @see \eZ\Publish\API\Repository\ContentService::loadRelations()
3688
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testAddRelation
3689
     */
3690
    public function testLoadRelations()
3691
    {
3692
        $repository = $this->getRepository();
3693
3694
        $contentService = $repository->getContentService();
3695
3696
        /* BEGIN: Use Case */
3697
        // Remote ids of the "Media" and the "eZ Publish Demo Design ..." page
3698
        // of a eZ Publish demo installation.
3699
        $mediaRemoteId = 'a6e35cbcb7cd6ae4b691f3eee30cd262';
3700
        $demoDesignRemoteId = '8b8b22fe3c6061ed500fbd2b377b885f';
3701
3702
        $draft = $this->createContentDraftVersion1();
3703
3704
        // Load other content objects
3705
        $media = $contentService->loadContentInfoByRemoteId($mediaRemoteId);
3706
        $demoDesign = $contentService->loadContentInfoByRemoteId($demoDesignRemoteId);
3707
3708
        // Create relation between new content object and "Media" page
3709
        $contentService->addRelation(
3710
            $draft->getVersionInfo(),
3711
            $media
3712
        );
3713
3714
        // Create another relation with the "Demo Design" page
3715
        $contentService->addRelation(
3716
            $draft->getVersionInfo(),
3717
            $demoDesign
3718
        );
3719
3720
        // Load all relations
3721
        $relations = $contentService->loadRelations($draft->getVersionInfo());
3722
        /* END: Use Case */
3723
3724
        usort(
3725
            $relations,
3726
            function ($rel1, $rel2) {
3727
                return strcasecmp(
3728
                    $rel2->getDestinationContentInfo()->remoteId,
3729
                    $rel1->getDestinationContentInfo()->remoteId
3730
                );
3731
            }
3732
        );
3733
3734
        $this->assertEquals(
3735
            [
3736
                [
3737
                    'sourceContentInfo' => 'abcdef0123456789abcdef0123456789',
3738
                    'destinationContentInfo' => 'a6e35cbcb7cd6ae4b691f3eee30cd262',
3739
                ],
3740
                [
3741
                    'sourceContentInfo' => 'abcdef0123456789abcdef0123456789',
3742
                    'destinationContentInfo' => '8b8b22fe3c6061ed500fbd2b377b885f',
3743
                ],
3744
            ],
3745
            [
3746
                [
3747
                    'sourceContentInfo' => $relations[0]->sourceContentInfo->remoteId,
3748
                    'destinationContentInfo' => $relations[0]->destinationContentInfo->remoteId,
3749
                ],
3750
                [
3751
                    'sourceContentInfo' => $relations[1]->sourceContentInfo->remoteId,
3752
                    'destinationContentInfo' => $relations[1]->destinationContentInfo->remoteId,
3753
                ],
3754
            ]
3755
        );
3756
    }
3757
3758
    /**
3759
     * Test for the loadRelations() method.
3760
     *
3761
     * @see \eZ\Publish\API\Repository\ContentService::loadRelations()
3762
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testAddRelation
3763
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadRelations
3764
     */
3765
    public function testLoadRelationsSkipsArchivedContent()
3766
    {
3767
        $repository = $this->getRepository();
3768
3769
        $contentService = $repository->getContentService();
3770
3771
        /* BEGIN: Use Case */
3772
        $trashService = $repository->getTrashService();
3773
        $locationService = $repository->getLocationService();
3774
        // Remote ids of the "Media" and the "eZ Publish Demo Design ..." page
3775
        // of a eZ Publish demo installation.
3776
        $mediaRemoteId = 'a6e35cbcb7cd6ae4b691f3eee30cd262';
3777
        $demoDesignRemoteId = '8b8b22fe3c6061ed500fbd2b377b885f';
3778
3779
        $draft = $this->createContentDraftVersion1();
3780
3781
        // Load other content objects
3782
        $media = $contentService->loadContentInfoByRemoteId($mediaRemoteId);
3783
        $demoDesign = $contentService->loadContentInfoByRemoteId($demoDesignRemoteId);
3784
3785
        // Create relation between new content object and "Media" page
3786
        $contentService->addRelation(
3787
            $draft->getVersionInfo(),
3788
            $media
3789
        );
3790
3791
        // Create another relation with the "Demo Design" page
3792
        $contentService->addRelation(
3793
            $draft->getVersionInfo(),
3794
            $demoDesign
3795
        );
3796
3797
        $demoDesignLocation = $locationService->loadLocation($demoDesign->mainLocationId);
3798
3799
        // Trashing Content's last Location will change its status to archived,
3800
        // in this case relation towards it will not be loaded.
3801
        $trashService->trash($demoDesignLocation);
3802
3803
        // Load all relations
3804
        $relations = $contentService->loadRelations($draft->getVersionInfo());
3805
        /* END: Use Case */
3806
3807
        $this->assertCount(1, $relations);
3808
        $this->assertEquals(
3809
            [
3810
                [
3811
                    'sourceContentInfo' => 'abcdef0123456789abcdef0123456789',
3812
                    'destinationContentInfo' => 'a6e35cbcb7cd6ae4b691f3eee30cd262',
3813
                ],
3814
            ],
3815
            [
3816
                [
3817
                    'sourceContentInfo' => $relations[0]->sourceContentInfo->remoteId,
3818
                    'destinationContentInfo' => $relations[0]->destinationContentInfo->remoteId,
3819
                ],
3820
            ]
3821
        );
3822
    }
3823
3824
    /**
3825
     * Test for the loadRelations() method.
3826
     *
3827
     * @see \eZ\Publish\API\Repository\ContentService::loadRelations()
3828
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testAddRelation
3829
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadRelations
3830
     */
3831
    public function testLoadRelationsSkipsDraftContent()
3832
    {
3833
        $repository = $this->getRepository();
3834
3835
        $contentService = $repository->getContentService();
3836
3837
        /* BEGIN: Use Case */
3838
        // Remote ids of the "Media" and the "eZ Publish Demo Design ..." page
3839
        // of a eZ Publish demo installation.
3840
        $mediaRemoteId = 'a6e35cbcb7cd6ae4b691f3eee30cd262';
3841
        $demoDesignRemoteId = '8b8b22fe3c6061ed500fbd2b377b885f';
3842
3843
        $draft = $this->createContentDraftVersion1();
3844
3845
        // Load other content objects
3846
        $media = $contentService->loadContentByRemoteId($mediaRemoteId);
3847
        $demoDesign = $contentService->loadContentInfoByRemoteId($demoDesignRemoteId);
3848
3849
        // Create draft of "Media" page
3850
        $mediaDraft = $contentService->createContentDraft($media->contentInfo);
3851
3852
        // Create relation between "Media" page and new content object draft.
3853
        // This relation will not be loaded before the draft is published.
3854
        $contentService->addRelation(
3855
            $mediaDraft->getVersionInfo(),
3856
            $draft->getVersionInfo()->getContentInfo()
3857
        );
3858
3859
        // Create another relation with the "Demo Design" page
3860
        $contentService->addRelation(
3861
            $mediaDraft->getVersionInfo(),
3862
            $demoDesign
3863
        );
3864
3865
        // Load all relations
3866
        $relations = $contentService->loadRelations($mediaDraft->getVersionInfo());
3867
        /* END: Use Case */
3868
3869
        $this->assertCount(1, $relations);
3870
        $this->assertEquals(
3871
            [
3872
                [
3873
                    'sourceContentInfo' => 'a6e35cbcb7cd6ae4b691f3eee30cd262',
3874
                    'destinationContentInfo' => '8b8b22fe3c6061ed500fbd2b377b885f',
3875
                ],
3876
            ],
3877
            [
3878
                [
3879
                    'sourceContentInfo' => $relations[0]->sourceContentInfo->remoteId,
3880
                    'destinationContentInfo' => $relations[0]->destinationContentInfo->remoteId,
3881
                ],
3882
            ]
3883
        );
3884
    }
3885
3886
    /**
3887
     * Test for the loadReverseRelations() method.
3888
     *
3889
     * @see \eZ\Publish\API\Repository\ContentService::loadReverseRelations()
3890
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testAddRelation
3891
     */
3892
    public function testLoadReverseRelations()
3893
    {
3894
        $repository = $this->getRepository();
3895
3896
        $contentService = $repository->getContentService();
3897
3898
        /* BEGIN: Use Case */
3899
        // Remote ids of the "Media" and the "eZ Publish Demo Design ..." page
3900
        // of a eZ Publish demo installation.
3901
        $mediaRemoteId = 'a6e35cbcb7cd6ae4b691f3eee30cd262';
3902
        $demoDesignRemoteId = '8b8b22fe3c6061ed500fbd2b377b885f';
3903
3904
        $versionInfo = $this->createContentVersion1()->getVersionInfo();
3905
        $contentInfo = $versionInfo->getContentInfo();
3906
3907
        // Create some drafts
3908
        $mediaDraft = $contentService->createContentDraft(
3909
            $contentService->loadContentInfoByRemoteId($mediaRemoteId)
3910
        );
3911
        $demoDesignDraft = $contentService->createContentDraft(
3912
            $contentService->loadContentInfoByRemoteId($demoDesignRemoteId)
3913
        );
3914
3915
        // Create relation between new content object and "Media" page
3916
        $relation1 = $contentService->addRelation(
3917
            $mediaDraft->getVersionInfo(),
3918
            $contentInfo
3919
        );
3920
3921
        // Create another relation with the "Demo Design" page
3922
        $relation2 = $contentService->addRelation(
3923
            $demoDesignDraft->getVersionInfo(),
3924
            $contentInfo
3925
        );
3926
3927
        // Publish drafts, so relations become active
3928
        $contentService->publishVersion($mediaDraft->getVersionInfo());
3929
        $contentService->publishVersion($demoDesignDraft->getVersionInfo());
3930
3931
        // Load all relations
3932
        $relations = $contentService->loadRelations($versionInfo);
3933
        $reverseRelations = $contentService->loadReverseRelations($contentInfo);
3934
        /* END: Use Case */
3935
3936
        $this->assertEquals($contentInfo->id, $relation1->getDestinationContentInfo()->id);
3937
        $this->assertEquals($mediaDraft->id, $relation1->getSourceContentInfo()->id);
3938
3939
        $this->assertEquals($contentInfo->id, $relation2->getDestinationContentInfo()->id);
3940
        $this->assertEquals($demoDesignDraft->id, $relation2->getSourceContentInfo()->id);
3941
3942
        $this->assertCount(0, $relations);
3943
        $this->assertCount(2, $reverseRelations);
3944
3945
        usort(
3946
            $reverseRelations,
3947
            function ($rel1, $rel2) {
3948
                return strcasecmp(
3949
                    $rel2->getSourceContentInfo()->remoteId,
3950
                    $rel1->getSourceContentInfo()->remoteId
3951
                );
3952
            }
3953
        );
3954
3955
        $this->assertEquals(
3956
            [
3957
                [
3958
                    'sourceContentInfo' => 'a6e35cbcb7cd6ae4b691f3eee30cd262',
3959
                    'destinationContentInfo' => 'abcdef0123456789abcdef0123456789',
3960
                ],
3961
                [
3962
                    'sourceContentInfo' => '8b8b22fe3c6061ed500fbd2b377b885f',
3963
                    'destinationContentInfo' => 'abcdef0123456789abcdef0123456789',
3964
                ],
3965
            ],
3966
            [
3967
                [
3968
                    'sourceContentInfo' => $reverseRelations[0]->sourceContentInfo->remoteId,
3969
                    'destinationContentInfo' => $reverseRelations[0]->destinationContentInfo->remoteId,
3970
                ],
3971
                [
3972
                    'sourceContentInfo' => $reverseRelations[1]->sourceContentInfo->remoteId,
3973
                    'destinationContentInfo' => $reverseRelations[1]->destinationContentInfo->remoteId,
3974
                ],
3975
            ]
3976
        );
3977
    }
3978
3979
    /**
3980
     * Test for the loadReverseRelations() method.
3981
     *
3982
     * @see \eZ\Publish\API\Repository\ContentService::loadReverseRelations()
3983
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testAddRelation
3984
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadReverseRelations
3985
     */
3986
    public function testLoadReverseRelationsSkipsArchivedContent()
3987
    {
3988
        $repository = $this->getRepository();
3989
3990
        $contentService = $repository->getContentService();
3991
3992
        /* BEGIN: Use Case */
3993
        $trashService = $repository->getTrashService();
3994
        $locationService = $repository->getLocationService();
3995
        // Remote ids of the "Media" and the "eZ Publish Demo Design ..." page
3996
        // of a eZ Publish demo installation.
3997
        $mediaRemoteId = 'a6e35cbcb7cd6ae4b691f3eee30cd262';
3998
        $demoDesignRemoteId = '8b8b22fe3c6061ed500fbd2b377b885f';
3999
4000
        $versionInfo = $this->createContentVersion1()->getVersionInfo();
4001
        $contentInfo = $versionInfo->getContentInfo();
4002
4003
        // Create some drafts
4004
        $mediaDraft = $contentService->createContentDraft(
4005
            $contentService->loadContentInfoByRemoteId($mediaRemoteId)
4006
        );
4007
        $demoDesignDraft = $contentService->createContentDraft(
4008
            $contentService->loadContentInfoByRemoteId($demoDesignRemoteId)
4009
        );
4010
4011
        // Create relation between new content object and "Media" page
4012
        $relation1 = $contentService->addRelation(
4013
            $mediaDraft->getVersionInfo(),
4014
            $contentInfo
4015
        );
4016
4017
        // Create another relation with the "Demo Design" page
4018
        $relation2 = $contentService->addRelation(
4019
            $demoDesignDraft->getVersionInfo(),
4020
            $contentInfo
4021
        );
4022
4023
        // Publish drafts, so relations become active
4024
        $contentService->publishVersion($mediaDraft->getVersionInfo());
4025
        $contentService->publishVersion($demoDesignDraft->getVersionInfo());
4026
4027
        $demoDesignLocation = $locationService->loadLocation($demoDesignDraft->contentInfo->mainLocationId);
4028
4029
        // Trashing Content's last Location will change its status to archived,
4030
        // in this case relation from it will not be loaded.
4031
        $trashService->trash($demoDesignLocation);
4032
4033
        // Load all relations
4034
        $relations = $contentService->loadRelations($versionInfo);
4035
        $reverseRelations = $contentService->loadReverseRelations($contentInfo);
4036
        /* END: Use Case */
4037
4038
        $this->assertEquals($contentInfo->id, $relation1->getDestinationContentInfo()->id);
4039
        $this->assertEquals($mediaDraft->id, $relation1->getSourceContentInfo()->id);
4040
4041
        $this->assertEquals($contentInfo->id, $relation2->getDestinationContentInfo()->id);
4042
        $this->assertEquals($demoDesignDraft->id, $relation2->getSourceContentInfo()->id);
4043
4044
        $this->assertCount(0, $relations);
4045
        $this->assertCount(1, $reverseRelations);
4046
4047
        $this->assertEquals(
4048
            [
4049
                [
4050
                    'sourceContentInfo' => 'a6e35cbcb7cd6ae4b691f3eee30cd262',
4051
                    'destinationContentInfo' => 'abcdef0123456789abcdef0123456789',
4052
                ],
4053
            ],
4054
            [
4055
                [
4056
                    'sourceContentInfo' => $reverseRelations[0]->sourceContentInfo->remoteId,
4057
                    'destinationContentInfo' => $reverseRelations[0]->destinationContentInfo->remoteId,
4058
                ],
4059
            ]
4060
        );
4061
    }
4062
4063
    /**
4064
     * Test for the loadReverseRelations() method.
4065
     *
4066
     * @see \eZ\Publish\API\Repository\ContentService::loadReverseRelations()
4067
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testAddRelation
4068
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadReverseRelations
4069
     */
4070
    public function testLoadReverseRelationsSkipsDraftContent()
4071
    {
4072
        $repository = $this->getRepository();
4073
4074
        $contentService = $repository->getContentService();
4075
4076
        /* BEGIN: Use Case */
4077
        // Remote ids of the "Media" and the "eZ Publish Demo Design ..." page
4078
        // of a eZ Publish demo installation.
4079
        $mediaRemoteId = 'a6e35cbcb7cd6ae4b691f3eee30cd262';
4080
        $demoDesignRemoteId = '8b8b22fe3c6061ed500fbd2b377b885f';
4081
4082
        // Load "Media" page Content
4083
        $media = $contentService->loadContentByRemoteId($mediaRemoteId);
4084
4085
        // Create some drafts
4086
        $newDraftVersionInfo = $this->createContentDraftVersion1()->getVersionInfo();
4087
        $demoDesignDraft = $contentService->createContentDraft(
4088
            $contentService->loadContentInfoByRemoteId($demoDesignRemoteId)
4089
        );
4090
4091
        // Create relation between "Media" page and new content object
4092
        $relation1 = $contentService->addRelation(
4093
            $newDraftVersionInfo,
4094
            $media->contentInfo
4095
        );
4096
4097
        // Create another relation with the "Demo Design" page
4098
        $relation2 = $contentService->addRelation(
4099
            $demoDesignDraft->getVersionInfo(),
4100
            $media->contentInfo
4101
        );
4102
4103
        // Publish drafts, so relations become active
4104
        $contentService->publishVersion($demoDesignDraft->getVersionInfo());
4105
        // We will not publish new Content draft, therefore relation from it
4106
        // will not be loaded as reverse relation for "Media" page
4107
        //$contentService->publishVersion( $newDraftVersionInfo );
4108
4109
        // Load all relations
4110
        $relations = $contentService->loadRelations($media->versionInfo);
4111
        $reverseRelations = $contentService->loadReverseRelations($media->contentInfo);
4112
        /* END: Use Case */
4113
4114
        $this->assertEquals($media->contentInfo->id, $relation1->getDestinationContentInfo()->id);
4115
        $this->assertEquals($newDraftVersionInfo->contentInfo->id, $relation1->getSourceContentInfo()->id);
4116
4117
        $this->assertEquals($media->contentInfo->id, $relation2->getDestinationContentInfo()->id);
4118
        $this->assertEquals($demoDesignDraft->id, $relation2->getSourceContentInfo()->id);
4119
4120
        $this->assertCount(0, $relations);
4121
        $this->assertCount(1, $reverseRelations);
4122
4123
        $this->assertEquals(
4124
            [
4125
                [
4126
                    'sourceContentInfo' => '8b8b22fe3c6061ed500fbd2b377b885f',
4127
                    'destinationContentInfo' => 'a6e35cbcb7cd6ae4b691f3eee30cd262',
4128
                ],
4129
            ],
4130
            [
4131
                [
4132
                    'sourceContentInfo' => $reverseRelations[0]->sourceContentInfo->remoteId,
4133
                    'destinationContentInfo' => $reverseRelations[0]->destinationContentInfo->remoteId,
4134
                ],
4135
            ]
4136
        );
4137
    }
4138
4139
    /**
4140
     * Test for the deleteRelation() method.
4141
     *
4142
     * @see \eZ\Publish\API\Repository\ContentService::deleteRelation()
4143
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadRelations
4144
     */
4145
    public function testDeleteRelation()
4146
    {
4147
        $repository = $this->getRepository();
4148
4149
        $contentService = $repository->getContentService();
4150
4151
        /* BEGIN: Use Case */
4152
        // Remote ids of the "Media" and the "Demo Design" page of a eZ Publish
4153
        // demo installation.
4154
        $mediaRemoteId = 'a6e35cbcb7cd6ae4b691f3eee30cd262';
4155
        $demoDesignRemoteId = '8b8b22fe3c6061ed500fbd2b377b885f';
4156
4157
        $draft = $this->createContentDraftVersion1();
4158
4159
        $media = $contentService->loadContentInfoByRemoteId($mediaRemoteId);
4160
        $demoDesign = $contentService->loadContentInfoByRemoteId($demoDesignRemoteId);
4161
4162
        // Establish some relations
4163
        $contentService->addRelation($draft->getVersionInfo(), $media);
4164
        $contentService->addRelation($draft->getVersionInfo(), $demoDesign);
4165
4166
        // Delete one of the currently created relations
4167
        $contentService->deleteRelation($draft->getVersionInfo(), $media);
4168
4169
        // The relations array now contains only one element
4170
        $relations = $contentService->loadRelations($draft->getVersionInfo());
4171
        /* END: Use Case */
4172
4173
        $this->assertCount(1, $relations);
4174
    }
4175
4176
    /**
4177
     * Test for the deleteRelation() method.
4178
     *
4179
     * @see \eZ\Publish\API\Repository\ContentService::deleteRelation()
4180
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testDeleteRelation
4181
     */
4182
    public function testDeleteRelationThrowsBadStateException()
4183
    {
4184
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\BadStateException::class);
4185
4186
        $repository = $this->getRepository();
4187
4188
        $contentService = $repository->getContentService();
4189
4190
        /* BEGIN: Use Case */
4191
        // RemoteId of the "Media" page of an eZ Publish demo installation
4192
        $mediaRemoteId = 'a6e35cbcb7cd6ae4b691f3eee30cd262';
4193
4194
        $content = $this->createContentVersion1();
4195
4196
        // Load the destination object
4197
        $media = $contentService->loadContentInfoByRemoteId($mediaRemoteId);
4198
4199
        // Create a new draft
4200
        $draftVersion2 = $contentService->createContentDraft($content->contentInfo);
4201
4202
        // Add a relation
4203
        $contentService->addRelation($draftVersion2->getVersionInfo(), $media);
4204
4205
        // Publish new version
4206
        $contentVersion2 = $contentService->publishVersion(
4207
            $draftVersion2->getVersionInfo()
4208
        );
4209
4210
        // This call will fail with a "BadStateException", because content is
4211
        // published and not a draft.
4212
        $contentService->deleteRelation(
4213
            $contentVersion2->getVersionInfo(),
4214
            $media
4215
        );
4216
        /* END: Use Case */
4217
    }
4218
4219
    /**
4220
     * Test for the deleteRelation() method.
4221
     *
4222
     * @see \eZ\Publish\API\Repository\ContentService::deleteRelation()
4223
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testDeleteRelation
4224
     */
4225
    public function testDeleteRelationThrowsInvalidArgumentException()
4226
    {
4227
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\InvalidArgumentException::class);
4228
4229
        $repository = $this->getRepository();
4230
4231
        $contentService = $repository->getContentService();
4232
4233
        /* BEGIN: Use Case */
4234
        // RemoteId of the "Media" page of an eZ Publish demo installation
4235
        $mediaRemoteId = 'a6e35cbcb7cd6ae4b691f3eee30cd262';
4236
4237
        $draft = $this->createContentDraftVersion1();
4238
4239
        // Load the destination object
4240
        $media = $contentService->loadContentInfoByRemoteId($mediaRemoteId);
4241
4242
        // This call will fail with a "InvalidArgumentException", because no
4243
        // relation exists between $draft and $media.
4244
        $contentService->deleteRelation(
4245
            $draft->getVersionInfo(),
4246
            $media
4247
        );
4248
        /* END: Use Case */
4249
    }
4250
4251
    /**
4252
     * Test for the createContent() method.
4253
     *
4254
     * @see \eZ\Publish\API\Repository\ContentService::createContent()
4255
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContent
4256
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContent
4257
     */
4258
    public function testCreateContentInTransactionWithRollback()
4259
    {
4260
        if ($this->isVersion4()) {
4261
            $this->markTestSkipped('This test requires eZ Publish 5');
4262
        }
4263
4264
        $repository = $this->getRepository();
4265
4266
        /* BEGIN: Use Case */
4267
        $contentTypeService = $repository->getContentTypeService();
4268
        $contentService = $repository->getContentService();
4269
4270
        // Start a transaction
4271
        $repository->beginTransaction();
4272
4273
        try {
4274
            $contentType = $contentTypeService->loadContentTypeByIdentifier('forum');
4275
4276
            // Get a content create struct and set mandatory properties
4277
            $contentCreate = $contentService->newContentCreateStruct($contentType, 'eng-US');
4278
            $contentCreate->setField('name', 'Sindelfingen forum');
4279
4280
            $contentCreate->remoteId = 'abcdef0123456789abcdef0123456789';
4281
            $contentCreate->alwaysAvailable = true;
4282
4283
            // Create a new content object
4284
            $contentId = $contentService->createContent($contentCreate)->id;
4285
        } catch (Exception $e) {
4286
            // Cleanup hanging transaction on error
4287
            $repository->rollback();
4288
            throw $e;
4289
        }
4290
4291
        // Rollback all changes
4292
        $repository->rollback();
4293
4294
        try {
4295
            // This call will fail with a "NotFoundException"
4296
            $contentService->loadContent($contentId);
4297
        } catch (NotFoundException $e) {
4298
            // This is expected
4299
            return;
4300
        }
4301
        /* END: Use Case */
4302
4303
        $this->fail('Content object still exists after rollback.');
4304
    }
4305
4306
    /**
4307
     * Test for the createContent() method.
4308
     *
4309
     * @see \eZ\Publish\API\Repository\ContentService::createContent()
4310
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContent
4311
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContent
4312
     */
4313
    public function testCreateContentInTransactionWithCommit()
4314
    {
4315
        if ($this->isVersion4()) {
4316
            $this->markTestSkipped('This test requires eZ Publish 5');
4317
        }
4318
4319
        $repository = $this->getRepository();
4320
4321
        /* BEGIN: Use Case */
4322
        $contentTypeService = $repository->getContentTypeService();
4323
        $contentService = $repository->getContentService();
4324
4325
        // Start a transaction
4326
        $repository->beginTransaction();
4327
4328
        try {
4329
            $contentType = $contentTypeService->loadContentTypeByIdentifier('forum');
4330
4331
            // Get a content create struct and set mandatory properties
4332
            $contentCreate = $contentService->newContentCreateStruct($contentType, 'eng-US');
4333
            $contentCreate->setField('name', 'Sindelfingen forum');
4334
4335
            $contentCreate->remoteId = 'abcdef0123456789abcdef0123456789';
4336
            $contentCreate->alwaysAvailable = true;
4337
4338
            // Create a new content object
4339
            $contentId = $contentService->createContent($contentCreate)->id;
4340
4341
            // Commit changes
4342
            $repository->commit();
4343
        } catch (Exception $e) {
4344
            // Cleanup hanging transaction on error
4345
            $repository->rollback();
4346
            throw $e;
4347
        }
4348
4349
        // Load the new content object
4350
        $content = $contentService->loadContent($contentId);
4351
        /* END: Use Case */
4352
4353
        $this->assertEquals($contentId, $content->id);
4354
    }
4355
4356
    /**
4357
     * Test for the createContent() method.
4358
     *
4359
     * @see \eZ\Publish\API\Repository\ContentService::createContent($contentCreateStruct, $locationCreateStructs)
4360
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentWithLocationCreateParameterDoesNotCreateLocationImmediately
4361
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentThrowsNotFoundException
4362
     */
4363
    public function testCreateContentWithLocationCreateParameterInTransactionWithRollback()
4364
    {
4365
        $repository = $this->getRepository();
4366
4367
        $contentService = $repository->getContentService();
4368
4369
        /* BEGIN: Use Case */
4370
        // Start a transaction
4371
        $repository->beginTransaction();
4372
4373
        try {
4374
            $draft = $this->createContentDraftVersion1();
4375
        } catch (Exception $e) {
4376
            // Cleanup hanging transaction on error
4377
            $repository->rollback();
4378
            throw $e;
4379
        }
4380
4381
        $contentId = $draft->id;
4382
4383
        // Roleback the transaction
4384
        $repository->rollback();
4385
4386
        try {
4387
            // This call will fail with a "NotFoundException"
4388
            $contentService->loadContent($contentId);
4389
        } catch (NotFoundException $e) {
4390
            return;
4391
        }
4392
        /* END: Use Case */
4393
4394
        $this->fail('Can still load content object after rollback.');
4395
    }
4396
4397
    /**
4398
     * Test for the createContent() method.
4399
     *
4400
     * @see \eZ\Publish\API\Repository\ContentService::createContent($contentCreateStruct, $locationCreateStructs)
4401
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentWithLocationCreateParameterDoesNotCreateLocationImmediately
4402
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentThrowsNotFoundException
4403
     */
4404
    public function testCreateContentWithLocationCreateParameterInTransactionWithCommit()
4405
    {
4406
        $repository = $this->getRepository();
4407
4408
        $contentService = $repository->getContentService();
4409
4410
        /* BEGIN: Use Case */
4411
        // Start a transaction
4412
        $repository->beginTransaction();
4413
4414
        try {
4415
            $draft = $this->createContentDraftVersion1();
4416
4417
            $contentId = $draft->id;
4418
4419
            // Roleback the transaction
4420
            $repository->commit();
4421
        } catch (Exception $e) {
4422
            // Cleanup hanging transaction on error
4423
            $repository->rollback();
4424
            throw $e;
4425
        }
4426
4427
        // Load the new content object
4428
        $content = $contentService->loadContent($contentId);
4429
        /* END: Use Case */
4430
4431
        $this->assertEquals($contentId, $content->id);
4432
    }
4433
4434
    /**
4435
     * Test for the createContentDraft() method.
4436
     *
4437
     * @see \eZ\Publish\API\Repository\ContentService::createContentDraft()
4438
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentDraft
4439
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContent
4440
     */
4441
    public function testCreateContentDraftInTransactionWithRollback()
4442
    {
4443
        $repository = $this->getRepository();
4444
4445
        $contentId = $this->generateId('object', 12);
4446
        /* BEGIN: Use Case */
4447
        // $contentId is the ID of the "Administrator users" user group
4448
4449
        // Get the content service
4450
        $contentService = $repository->getContentService();
4451
4452
        // Load the user group content object
4453
        $content = $contentService->loadContent($contentId);
4454
4455
        // Start a new transaction
4456
        $repository->beginTransaction();
4457
4458
        try {
4459
            // Create a new draft
4460
            $drafted = $contentService->createContentDraft($content->contentInfo);
4461
4462
            // Store version number for later reuse
4463
            $versionNo = $drafted->versionInfo->versionNo;
4464
        } catch (Exception $e) {
4465
            // Cleanup hanging transaction on error
4466
            $repository->rollback();
4467
            throw $e;
4468
        }
4469
4470
        // Rollback
4471
        $repository->rollback();
4472
4473
        try {
4474
            // This call will fail with a "NotFoundException"
4475
            $contentService->loadContent($contentId, null, $versionNo);
4476
        } catch (NotFoundException $e) {
4477
            return;
4478
        }
4479
        /* END: Use Case */
4480
4481
        $this->fail('Can still load content draft after rollback');
4482
    }
4483
4484
    /**
4485
     * Test for the createContentDraft() method.
4486
     *
4487
     * @see \eZ\Publish\API\Repository\ContentService::createContentDraft()
4488
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContentDraft
4489
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContent
4490
     */
4491
    public function testCreateContentDraftInTransactionWithCommit()
4492
    {
4493
        $repository = $this->getRepository();
4494
4495
        $contentId = $this->generateId('object', 12);
4496
        /* BEGIN: Use Case */
4497
        // $contentId is the ID of the "Administrator users" user group
4498
4499
        // Get the content service
4500
        $contentService = $repository->getContentService();
4501
4502
        // Load the user group content object
4503
        $content = $contentService->loadContent($contentId);
4504
4505
        // Start a new transaction
4506
        $repository->beginTransaction();
4507
4508
        try {
4509
            // Create a new draft
4510
            $drafted = $contentService->createContentDraft($content->contentInfo);
4511
4512
            // Store version number for later reuse
4513
            $versionNo = $drafted->versionInfo->versionNo;
4514
4515
            // Commit all changes
4516
            $repository->commit();
4517
        } catch (Exception $e) {
4518
            // Cleanup hanging transaction on error
4519
            $repository->rollback();
4520
            throw $e;
4521
        }
4522
4523
        $content = $contentService->loadContent($contentId, null, $versionNo);
4524
        /* END: Use Case */
4525
4526
        $this->assertEquals(
4527
            $versionNo,
4528
            $content->getVersionInfo()->versionNo
4529
        );
4530
    }
4531
4532
    /**
4533
     * Test for the publishVersion() method.
4534
     *
4535
     * @see \eZ\Publish\API\Repository\ContentService::publishVersion()
4536
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersion
4537
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContent
4538
     */
4539
    public function testPublishVersionInTransactionWithRollback()
4540
    {
4541
        $repository = $this->getRepository();
4542
4543
        $contentId = $this->generateId('object', 12);
4544
        /* BEGIN: Use Case */
4545
        // $contentId is the ID of the "Administrator users" user group
4546
4547
        // Get the content service
4548
        $contentService = $repository->getContentService();
4549
4550
        // Load the user group content object
4551
        $content = $contentService->loadContent($contentId);
4552
4553
        // Start a new transaction
4554
        $repository->beginTransaction();
4555
4556
        try {
4557
            $draftVersion = $contentService->createContentDraft($content->contentInfo)->getVersionInfo();
4558
4559
            // Publish a new version
4560
            $content = $contentService->publishVersion($draftVersion);
4561
4562
            // Store version number for later reuse
4563
            $versionNo = $content->versionInfo->versionNo;
4564
        } catch (Exception $e) {
4565
            // Cleanup hanging transaction on error
4566
            $repository->rollback();
4567
            throw $e;
4568
        }
4569
4570
        // Rollback
4571
        $repository->rollback();
4572
4573
        try {
4574
            // This call will fail with a "NotFoundException"
4575
            $contentService->loadContent($contentId, null, $versionNo);
4576
        } catch (NotFoundException $e) {
4577
            return;
4578
        }
4579
        /* END: Use Case */
4580
4581
        $this->fail('Can still load content draft after rollback');
4582
    }
4583
4584
    /**
4585
     * Test for the publishVersion() method.
4586
     *
4587
     * @see \eZ\Publish\API\Repository\ContentService::publishVersion()
4588
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testPublishVersion
4589
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadVersionInfo
4590
     */
4591
    public function testPublishVersionInTransactionWithCommit()
4592
    {
4593
        $repository = $this->getRepository();
4594
4595
        /* BEGIN: Use Case */
4596
        // ID of the "Administrator users" user group
4597
        $contentId = 12;
4598
4599
        // Get the content service
4600
        $contentService = $repository->getContentService();
4601
4602
        // Load the user group content object
4603
        $template = $contentService->loadContent($contentId);
4604
4605
        // Start a new transaction
4606
        $repository->beginTransaction();
4607
4608
        try {
4609
            // Publish a new version
4610
            $content = $contentService->publishVersion(
4611
                $contentService->createContentDraft($template->contentInfo)->getVersionInfo()
4612
            );
4613
4614
            // Store version number for later reuse
4615
            $versionNo = $content->versionInfo->versionNo;
4616
4617
            // Commit all changes
4618
            $repository->commit();
4619
        } catch (Exception $e) {
4620
            // Cleanup hanging transaction on error
4621
            $repository->rollback();
4622
            throw $e;
4623
        }
4624
4625
        // Load current version info
4626
        $versionInfo = $contentService->loadVersionInfo($content->contentInfo);
4627
        /* END: Use Case */
4628
4629
        $this->assertEquals($versionNo, $versionInfo->versionNo);
4630
    }
4631
4632
    /**
4633
     * Test for the updateContent() method.
4634
     *
4635
     * @see \eZ\Publish\API\Repository\ContentService::updateContent()
4636
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContent
4637
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContent
4638
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentInfo
4639
     */
4640
    public function testUpdateContentInTransactionWithRollback()
4641
    {
4642
        $repository = $this->getRepository();
4643
4644
        $contentId = $this->generateId('object', 12);
4645
        /* BEGIN: Use Case */
4646
        // $contentId is the ID of the "Administrator users" user group
4647
4648
        // Load content service
4649
        $contentService = $repository->getContentService();
4650
4651
        // Create a new user group draft
4652
        $draft = $contentService->createContentDraft(
4653
            $contentService->loadContentInfo($contentId)
4654
        );
4655
4656
        // Get an update struct and change the group name
4657
        $contentUpdate = $contentService->newContentUpdateStruct();
4658
        $contentUpdate->setField('name', 'Administrators', 'eng-US');
4659
4660
        // Start a transaction
4661
        $repository->beginTransaction();
4662
4663
        try {
4664
            // Update the group name
4665
            $draft = $contentService->updateContent(
4666
                $draft->getVersionInfo(),
4667
                $contentUpdate
4668
            );
4669
4670
            // Publish updated version
4671
            $contentService->publishVersion($draft->getVersionInfo());
4672
        } catch (Exception $e) {
4673
            // Cleanup hanging transaction on error
4674
            $repository->rollback();
4675
            throw $e;
4676
        }
4677
4678
        // Rollback all changes.
4679
        $repository->rollback();
4680
4681
        // Name will still be "Administrator users"
4682
        $name = $contentService->loadContent($contentId)->getFieldValue('name');
4683
        /* END: Use Case */
4684
4685
        $this->assertEquals('Administrator users', $name);
4686
    }
4687
4688
    /**
4689
     * Test for the updateContent() method.
4690
     *
4691
     * @see \eZ\Publish\API\Repository\ContentService::updateContent()
4692
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContent
4693
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContent
4694
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentInfo
4695
     */
4696
    public function testUpdateContentInTransactionWithCommit()
4697
    {
4698
        $repository = $this->getRepository();
4699
4700
        $contentId = $this->generateId('object', 12);
4701
        /* BEGIN: Use Case */
4702
        // $contentId is the ID of the "Administrator users" user group
4703
4704
        // Load content service
4705
        $contentService = $repository->getContentService();
4706
4707
        // Create a new user group draft
4708
        $draft = $contentService->createContentDraft(
4709
            $contentService->loadContentInfo($contentId)
4710
        );
4711
4712
        // Get an update struct and change the group name
4713
        $contentUpdate = $contentService->newContentUpdateStruct();
4714
        $contentUpdate->setField('name', 'Administrators', 'eng-US');
4715
4716
        // Start a transaction
4717
        $repository->beginTransaction();
4718
4719
        try {
4720
            // Update the group name
4721
            $draft = $contentService->updateContent(
4722
                $draft->getVersionInfo(),
4723
                $contentUpdate
4724
            );
4725
4726
            // Publish updated version
4727
            $contentService->publishVersion($draft->getVersionInfo());
4728
4729
            // Commit all changes.
4730
            $repository->commit();
4731
        } catch (Exception $e) {
4732
            // Cleanup hanging transaction on error
4733
            $repository->rollback();
4734
            throw $e;
4735
        }
4736
4737
        // Name is now "Administrators"
4738
        $name = $contentService->loadContent($contentId)->getFieldValue('name', 'eng-US');
4739
        /* END: Use Case */
4740
4741
        $this->assertEquals('Administrators', $name);
4742
    }
4743
4744
    /**
4745
     * Test for the updateContentMetadata() method.
4746
     *
4747
     * @see \eZ\Publish\API\Repository\ContentService::updateContentMetadata()
4748
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContentMetadata
4749
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentInfo
4750
     */
4751
    public function testUpdateContentMetadataInTransactionWithRollback()
4752
    {
4753
        $repository = $this->getRepository();
4754
4755
        $contentId = $this->generateId('object', 12);
4756
        /* BEGIN: Use Case */
4757
        // $contentId is the ID of the "Administrator users" user group
4758
4759
        // Get the content service
4760
        $contentService = $repository->getContentService();
4761
4762
        // Load a ContentInfo object
4763
        $contentInfo = $contentService->loadContentInfo($contentId);
4764
4765
        // Store remoteId for later testing
4766
        $remoteId = $contentInfo->remoteId;
4767
4768
        // Start a transaction
4769
        $repository->beginTransaction();
4770
4771
        try {
4772
            // Get metadata update struct and change remoteId
4773
            $metadataUpdate = $contentService->newContentMetadataUpdateStruct();
4774
            $metadataUpdate->remoteId = md5(microtime(true));
4775
4776
            // Update the metadata of the published content object
4777
            $contentService->updateContentMetadata(
4778
                $contentInfo,
4779
                $metadataUpdate
4780
            );
4781
        } catch (Exception $e) {
4782
            // Cleanup hanging transaction on error
4783
            $repository->rollback();
4784
            throw $e;
4785
        }
4786
4787
        // Rollback all changes.
4788
        $repository->rollback();
4789
4790
        // Load current remoteId
4791
        $remoteIdReloaded = $contentService->loadContentInfo($contentId)->remoteId;
4792
        /* END: Use Case */
4793
4794
        $this->assertEquals($remoteId, $remoteIdReloaded);
4795
    }
4796
4797
    /**
4798
     * Test for the updateContentMetadata() method.
4799
     *
4800
     * @see \eZ\Publish\API\Repository\ContentService::updateContentMetadata()
4801
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContentMetadata
4802
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentInfo
4803
     */
4804
    public function testUpdateContentMetadataInTransactionWithCommit()
4805
    {
4806
        $repository = $this->getRepository();
4807
4808
        $contentId = $this->generateId('object', 12);
4809
        /* BEGIN: Use Case */
4810
        // $contentId is the ID of the "Administrator users" user group
4811
4812
        // Get the content service
4813
        $contentService = $repository->getContentService();
4814
4815
        // Load a ContentInfo object
4816
        $contentInfo = $contentService->loadContentInfo($contentId);
4817
4818
        // Store remoteId for later testing
4819
        $remoteId = $contentInfo->remoteId;
4820
4821
        // Start a transaction
4822
        $repository->beginTransaction();
4823
4824
        try {
4825
            // Get metadata update struct and change remoteId
4826
            $metadataUpdate = $contentService->newContentMetadataUpdateStruct();
4827
            $metadataUpdate->remoteId = md5(microtime(true));
4828
4829
            // Update the metadata of the published content object
4830
            $contentService->updateContentMetadata(
4831
                $contentInfo,
4832
                $metadataUpdate
4833
            );
4834
4835
            // Commit all changes.
4836
            $repository->commit();
4837
        } catch (Exception $e) {
4838
            // Cleanup hanging transaction on error
4839
            $repository->rollback();
4840
            throw $e;
4841
        }
4842
4843
        // Load current remoteId
4844
        $remoteIdReloaded = $contentService->loadContentInfo($contentId)->remoteId;
4845
        /* END: Use Case */
4846
4847
        $this->assertNotEquals($remoteId, $remoteIdReloaded);
4848
    }
4849
4850
    /**
4851
     * Test for the deleteVersion() method.
4852
     *
4853
     * @see \eZ\Publish\API\Repository\ContentService::deleteVersion()
4854
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContent
4855
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentInfo
4856
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentDrafts
4857
     */
4858
    public function testDeleteVersionInTransactionWithRollback()
4859
    {
4860
        $repository = $this->getRepository();
4861
4862
        $contentId = $this->generateId('object', 12);
4863
        /* BEGIN: Use Case */
4864
        // $contentId is the ID of the "Administrator users" user group
4865
4866
        // Get the content service
4867
        $contentService = $repository->getContentService();
4868
4869
        // Start a new transaction
4870
        $repository->beginTransaction();
4871
4872
        try {
4873
            // Create a new draft
4874
            $draft = $contentService->createContentDraft(
4875
                $contentService->loadContentInfo($contentId)
4876
            );
4877
4878
            $contentService->deleteVersion($draft->getVersionInfo());
4879
        } catch (Exception $e) {
4880
            // Cleanup hanging transaction on error
4881
            $repository->rollback();
4882
            throw $e;
4883
        }
4884
4885
        // Rollback all changes.
4886
        $repository->rollback();
4887
4888
        // This array will be empty
4889
        $drafts = $contentService->loadContentDrafts();
4890
        /* END: Use Case */
4891
4892
        $this->assertSame([], $drafts);
4893
    }
4894
4895
    /**
4896
     * Test for the deleteVersion() method.
4897
     *
4898
     * @see \eZ\Publish\API\Repository\ContentService::deleteVersion()
4899
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContent
4900
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentInfo
4901
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentDrafts
4902
     */
4903
    public function testDeleteVersionInTransactionWithCommit()
4904
    {
4905
        $repository = $this->getRepository();
4906
4907
        $contentId = $this->generateId('object', 12);
4908
        /* BEGIN: Use Case */
4909
        // $contentId is the ID of the "Administrator users" user group
4910
4911
        // Get the content service
4912
        $contentService = $repository->getContentService();
4913
4914
        // Start a new transaction
4915
        $repository->beginTransaction();
4916
4917
        try {
4918
            // Create a new draft
4919
            $draft = $contentService->createContentDraft(
4920
                $contentService->loadContentInfo($contentId)
4921
            );
4922
4923
            $contentService->deleteVersion($draft->getVersionInfo());
4924
4925
            // Commit all changes.
4926
            $repository->commit();
4927
        } catch (Exception $e) {
4928
            // Cleanup hanging transaction on error
4929
            $repository->rollback();
4930
            throw $e;
4931
        }
4932
4933
        // This array will contain no element
4934
        $drafts = $contentService->loadContentDrafts();
4935
        /* END: Use Case */
4936
4937
        $this->assertSame([], $drafts);
4938
    }
4939
4940
    /**
4941
     * Test for the deleteContent() method.
4942
     *
4943
     * @see \eZ\Publish\API\Repository\ContentService::deleteContent()
4944
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testDeleteContent
4945
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentInfo
4946
     */
4947
    public function testDeleteContentInTransactionWithRollback()
4948
    {
4949
        $repository = $this->getRepository();
4950
4951
        $contentId = $this->generateId('object', 11);
4952
        /* BEGIN: Use Case */
4953
        // $contentId is the ID of the "Members" user group in an eZ Publish
4954
        // demo installation
4955
4956
        // Get content service
4957
        $contentService = $repository->getContentService();
4958
4959
        // Load a ContentInfo instance
4960
        $contentInfo = $contentService->loadContentInfo($contentId);
4961
4962
        // Start a new transaction
4963
        $repository->beginTransaction();
4964
4965
        try {
4966
            // Delete content object
4967
            $contentService->deleteContent($contentInfo);
4968
        } catch (Exception $e) {
4969
            // Cleanup hanging transaction on error
4970
            $repository->rollback();
4971
            throw $e;
4972
        }
4973
4974
        // Rollback all changes
4975
        $repository->rollback();
4976
4977
        // This call will return the original content object
4978
        $contentInfo = $contentService->loadContentInfo($contentId);
4979
        /* END: Use Case */
4980
4981
        $this->assertEquals($contentId, $contentInfo->id);
4982
    }
4983
4984
    /**
4985
     * Test for the deleteContent() method.
4986
     *
4987
     * @see \eZ\Publish\API\Repository\ContentService::deleteContent()
4988
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testDeleteContent
4989
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testLoadContentInfo
4990
     */
4991
    public function testDeleteContentInTransactionWithCommit()
4992
    {
4993
        $repository = $this->getRepository();
4994
4995
        $contentId = $this->generateId('object', 11);
4996
        /* BEGIN: Use Case */
4997
        // $contentId is the ID of the "Members" user group in an eZ Publish
4998
        // demo installation
4999
5000
        // Get content service
5001
        $contentService = $repository->getContentService();
5002
5003
        // Load a ContentInfo instance
5004
        $contentInfo = $contentService->loadContentInfo($contentId);
5005
5006
        // Start a new transaction
5007
        $repository->beginTransaction();
5008
5009
        try {
5010
            // Delete content object
5011
            $contentService->deleteContent($contentInfo);
5012
5013
            // Commit all changes
5014
            $repository->commit();
5015
        } catch (Exception $e) {
5016
            // Cleanup hanging transaction on error
5017
            $repository->rollback();
5018
            throw $e;
5019
        }
5020
5021
        // Deleted content info is not found anymore
5022
        try {
5023
            $contentService->loadContentInfo($contentId);
5024
        } catch (NotFoundException $e) {
5025
            return;
5026
        }
5027
        /* END: Use Case */
5028
5029
        $this->fail('Can still load ContentInfo after commit.');
5030
    }
5031
5032
    /**
5033
     * Test for the copyContent() method.
5034
     *
5035
     * @see \eZ\Publish\API\Repository\ContentService::copyContent()
5036
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCopyContent
5037
     * @depend(s) eZ\Publish\API\Repository\Tests\LocationServiceTest::testNewLocationCreateStruct
5038
     * @depend(s) eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocationChildren
5039
     * @depend(s) eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
5040
     */
5041
    public function testCopyContentInTransactionWithRollback()
5042
    {
5043
        $repository = $this->getRepository();
5044
5045
        $contentId = $this->generateId('object', 11);
5046
        $locationId = $this->generateId('location', 13);
5047
        /* BEGIN: Use Case */
5048
        // $contentId is the ID of the "Members" user group in an eZ Publish
5049
        // demo installation
5050
5051
        // $locationId is the ID of the "Administrator users" group location
5052
5053
        // Get services
5054
        $contentService = $repository->getContentService();
5055
        $locationService = $repository->getLocationService();
5056
5057
        // Load content object to copy
5058
        $content = $contentService->loadContent($contentId);
5059
5060
        // Create new target location
5061
        $locationCreate = $locationService->newLocationCreateStruct($locationId);
5062
5063
        // Start a new transaction
5064
        $repository->beginTransaction();
5065
5066
        try {
5067
            // Copy content with all versions and drafts
5068
            $contentService->copyContent(
5069
                $content->contentInfo,
5070
                $locationCreate
5071
            );
5072
        } catch (Exception $e) {
5073
            // Cleanup hanging transaction on error
5074
            $repository->rollback();
5075
            throw $e;
5076
        }
5077
5078
        // Rollback all changes
5079
        $repository->rollback();
5080
5081
        $this->refreshSearch($repository);
5082
5083
        // This array will only contain a single admin user object
5084
        $locations = $locationService->loadLocationChildren(
5085
            $locationService->loadLocation($locationId)
5086
        )->locations;
5087
        /* END: Use Case */
5088
5089
        $this->assertCount(1, $locations);
5090
    }
5091
5092
    /**
5093
     * Test for the copyContent() method.
5094
     *
5095
     * @see \eZ\Publish\API\Repository\ContentService::copyContent()
5096
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCopyContent
5097
     * @depend(s) eZ\Publish\API\Repository\Tests\LocationServiceTest::testNewLocationCreateStruct
5098
     * @depend(s) eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocationChildren
5099
     * @depend(s) eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
5100
     */
5101
    public function testCopyContentInTransactionWithCommit()
5102
    {
5103
        $repository = $this->getRepository();
5104
5105
        $contentId = $this->generateId('object', 11);
5106
        $locationId = $this->generateId('location', 13);
5107
        /* BEGIN: Use Case */
5108
        // $contentId is the ID of the "Members" user group in an eZ Publish
5109
        // demo installation
5110
5111
        // $locationId is the ID of the "Administrator users" group location
5112
5113
        // Get services
5114
        $contentService = $repository->getContentService();
5115
        $locationService = $repository->getLocationService();
5116
5117
        // Load content object to copy
5118
        $content = $contentService->loadContent($contentId);
5119
5120
        // Create new target location
5121
        $locationCreate = $locationService->newLocationCreateStruct($locationId);
5122
5123
        // Start a new transaction
5124
        $repository->beginTransaction();
5125
5126
        try {
5127
            // Copy content with all versions and drafts
5128
            $contentCopied = $contentService->copyContent(
5129
                $content->contentInfo,
5130
                $locationCreate
5131
            );
5132
5133
            // Commit all changes
5134
            $repository->commit();
5135
        } catch (Exception $e) {
5136
            // Cleanup hanging transaction on error
5137
            $repository->rollback();
5138
            throw $e;
5139
        }
5140
5141
        $this->refreshSearch($repository);
5142
5143
        // This will contain the admin user and the new child location
5144
        $locations = $locationService->loadLocationChildren(
5145
            $locationService->loadLocation($locationId)
5146
        )->locations;
5147
        /* END: Use Case */
5148
5149
        $this->assertCount(2, $locations);
5150
    }
5151
5152
    public function testURLAliasesCreatedForNewContent()
5153
    {
5154
        $repository = $this->getRepository();
5155
5156
        $contentService = $repository->getContentService();
5157
        $locationService = $repository->getLocationService();
5158
        $urlAliasService = $repository->getURLAliasService();
5159
5160
        /* BEGIN: Use Case */
5161
        $draft = $this->createContentDraftVersion1();
5162
5163
        // Automatically creates a new URLAlias for the content
5164
        $liveContent = $contentService->publishVersion($draft->getVersionInfo());
5165
        /* END: Use Case */
5166
5167
        $location = $locationService->loadLocation(
5168
            $liveContent->getVersionInfo()->getContentInfo()->mainLocationId
5169
        );
5170
5171
        $aliases = $urlAliasService->listLocationAliases($location, false);
5172
5173
        $this->assertAliasesCorrect(
5174
            [
5175
                '/Design/Plain-site/An-awesome-forum' => [
5176
                    'type' => URLAlias::LOCATION,
5177
                    'destination' => $location->id,
5178
                    'path' => '/Design/Plain-site/An-awesome-forum',
5179
                    'languageCodes' => ['eng-US'],
5180
                    'isHistory' => false,
5181
                    'isCustom' => false,
5182
                    'forward' => false,
5183
                ],
5184
            ],
5185
            $aliases
5186
        );
5187
    }
5188
5189
    public function testURLAliasesCreatedForUpdatedContent()
5190
    {
5191
        $repository = $this->getRepository();
5192
5193
        $contentService = $repository->getContentService();
5194
        $locationService = $repository->getLocationService();
5195
        $urlAliasService = $repository->getURLAliasService();
5196
5197
        /* BEGIN: Use Case */
5198
        $draft = $this->createUpdatedDraftVersion2();
5199
5200
        $location = $locationService->loadLocation(
5201
            $draft->getVersionInfo()->getContentInfo()->mainLocationId
5202
        );
5203
5204
        // Load and assert URL aliases before publishing updated Content, so that
5205
        // SPI cache is warmed up and cache invalidation is also tested.
5206
        $aliases = $urlAliasService->listLocationAliases($location, false);
5207
5208
        $this->assertAliasesCorrect(
5209
            [
5210
                '/Design/Plain-site/An-awesome-forum' => [
5211
                    'type' => URLAlias::LOCATION,
5212
                    'destination' => $location->id,
5213
                    'path' => '/Design/Plain-site/An-awesome-forum',
5214
                    'languageCodes' => ['eng-US'],
5215
                    'alwaysAvailable' => true,
5216
                    'isHistory' => false,
5217
                    'isCustom' => false,
5218
                    'forward' => false,
5219
                ],
5220
            ],
5221
            $aliases
5222
        );
5223
5224
        // Automatically marks old aliases for the content as history
5225
        // and creates new aliases, based on the changes
5226
        $liveContent = $contentService->publishVersion($draft->getVersionInfo());
5227
        /* END: Use Case */
5228
5229
        $location = $locationService->loadLocation(
5230
            $liveContent->getVersionInfo()->getContentInfo()->mainLocationId
5231
        );
5232
5233
        $aliases = $urlAliasService->listLocationAliases($location, false);
5234
5235
        $this->assertAliasesCorrect(
5236
            [
5237
                '/Design/Plain-site/An-awesome-forum2' => [
5238
                    'type' => URLAlias::LOCATION,
5239
                    'destination' => $location->id,
5240
                    'path' => '/Design/Plain-site/An-awesome-forum2',
5241
                    'languageCodes' => ['eng-US'],
5242
                    'alwaysAvailable' => true,
5243
                    'isHistory' => false,
5244
                    'isCustom' => false,
5245
                    'forward' => false,
5246
                ],
5247
                '/Design/Plain-site/An-awesome-forum23' => [
5248
                    'type' => URLAlias::LOCATION,
5249
                    'destination' => $location->id,
5250
                    'path' => '/Design/Plain-site/An-awesome-forum23',
5251
                    'languageCodes' => ['eng-GB'],
5252
                    'alwaysAvailable' => true,
5253
                    'isHistory' => false,
5254
                    'isCustom' => false,
5255
                    'forward' => false,
5256
                ],
5257
            ],
5258
            $aliases
5259
        );
5260
    }
5261
5262
    public function testCustomURLAliasesNotHistorizedOnUpdatedContent()
5263
    {
5264
        $repository = $this->getRepository();
5265
5266
        $contentService = $repository->getContentService();
5267
5268
        /* BEGIN: Use Case */
5269
        $urlAliasService = $repository->getURLAliasService();
5270
        $locationService = $repository->getLocationService();
5271
5272
        $content = $this->createContentVersion1();
5273
5274
        // Create a custom URL alias
5275
        $urlAliasService->createUrlAlias(
5276
            $locationService->loadLocation(
5277
                $content->getVersionInfo()->getContentInfo()->mainLocationId
5278
            ),
5279
            '/my/fancy/story-about-ez-publish',
5280
            'eng-US'
5281
        );
5282
5283
        $draftVersion2 = $contentService->createContentDraft($content->contentInfo);
5284
5285
        $contentUpdate = $contentService->newContentUpdateStruct();
5286
        $contentUpdate->initialLanguageCode = 'eng-US';
5287
        $contentUpdate->setField('name', 'Amazing Bielefeld forum');
5288
5289
        $draftVersion2 = $contentService->updateContent(
5290
            $draftVersion2->getVersionInfo(),
5291
            $contentUpdate
5292
        );
5293
5294
        // Only marks auto-generated aliases as history
5295
        // the custom one is left untouched
5296
        $liveContent = $contentService->publishVersion($draftVersion2->getVersionInfo());
5297
        /* END: Use Case */
5298
5299
        $location = $locationService->loadLocation(
5300
            $liveContent->getVersionInfo()->getContentInfo()->mainLocationId
5301
        );
5302
5303
        $aliases = $urlAliasService->listLocationAliases($location);
5304
5305
        $this->assertAliasesCorrect(
5306
            [
5307
                '/my/fancy/story-about-ez-publish' => [
5308
                    'type' => URLAlias::LOCATION,
5309
                    'destination' => $location->id,
5310
                    'path' => '/my/fancy/story-about-ez-publish',
5311
                    'languageCodes' => ['eng-US'],
5312
                    'isHistory' => false,
5313
                    'isCustom' => true,
5314
                    'forward' => false,
5315
                    'alwaysAvailable' => false,
5316
                ],
5317
            ],
5318
            $aliases
5319
        );
5320
    }
5321
5322
    /**
5323
     * Test to ensure that old versions are not affected by updates to newer
5324
     * drafts.
5325
     */
5326
    public function testUpdatingDraftDoesNotUpdateOldVersions()
5327
    {
5328
        $repository = $this->getRepository();
5329
5330
        $contentService = $repository->getContentService();
5331
5332
        $contentVersion2 = $this->createContentVersion2();
5333
5334
        $loadedContent1 = $contentService->loadContent($contentVersion2->id, null, 1);
5335
        $loadedContent2 = $contentService->loadContent($contentVersion2->id, null, 2);
5336
5337
        $this->assertNotEquals(
5338
            $loadedContent1->getFieldValue('name', 'eng-US'),
5339
            $loadedContent2->getFieldValue('name', 'eng-US')
5340
        );
5341
    }
5342
5343
    /**
5344
     * Test scenario with writer and publisher users.
5345
     * Writer can only create content. Publisher can publish this content.
5346
     */
5347
    public function testPublishWorkflow()
5348
    {
5349
        $repository = $this->getRepository();
5350
        $contentService = $repository->getContentService();
5351
5352
        $this->createRoleWithPolicies('Publisher', [
5353
            ['module' => 'content', 'function' => 'read'],
5354
            ['module' => 'content', 'function' => 'create'],
5355
            ['module' => 'content', 'function' => 'publish'],
5356
        ]);
5357
5358
        $this->createRoleWithPolicies('Writer', [
5359
            ['module' => 'content', 'function' => 'read'],
5360
            ['module' => 'content', 'function' => 'create'],
5361
        ]);
5362
5363
        $writerUser = $this->createCustomUserWithLogin(
5364
            'writer',
5365
            '[email protected]',
5366
            'Writers',
5367
            'Writer'
5368
        );
5369
5370
        $publisherUser = $this->createCustomUserWithLogin(
5371
            'publisher',
5372
            '[email protected]',
5373
            'Publishers',
5374
            'Publisher'
5375
        );
5376
5377
        $repository->getPermissionResolver()->setCurrentUserReference($writerUser);
5378
        $draft = $this->createContentDraftVersion1();
5379
5380
        $repository->getPermissionResolver()->setCurrentUserReference($publisherUser);
5381
        $content = $contentService->publishVersion($draft->versionInfo);
5382
5383
        $contentService->loadContent($content->id);
5384
    }
5385
5386
    /**
5387
     * Test publish / content policy is required to be able to publish content.
5388
     */
5389
    public function testPublishContentWithoutPublishPolicyThrowsException()
5390
    {
5391
        $this->expectException(\eZ\Publish\Core\Base\Exceptions\UnauthorizedException::class);
5392
        $this->expectExceptionMessageRegExp('/User does not have access to \'publish\' \'content\'/');
5393
5394
        $repository = $this->getRepository();
5395
5396
        $this->createRoleWithPolicies('Writer', [
5397
            ['module' => 'content', 'function' => 'read'],
5398
            ['module' => 'content', 'function' => 'create'],
5399
            ['module' => 'content', 'function' => 'edit'],
5400
        ]);
5401
        $writerUser = $this->createCustomUserWithLogin(
5402
            'writer',
5403
            '[email protected]',
5404
            'Writers',
5405
            'Writer'
5406
        );
5407
        $repository->getPermissionResolver()->setCurrentUserReference($writerUser);
5408
5409
        $this->createContentVersion1();
5410
    }
5411
5412
    /**
5413
     * Test removal of the specific translation from all the Versions of a Content Object.
5414
     *
5415
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteTranslation
5416
     */
5417
    public function testDeleteTranslation()
5418
    {
5419
        $repository = $this->getRepository();
5420
        $contentService = $repository->getContentService();
5421
        $content = $this->createContentVersion2();
5422
5423
        // create multiple versions to exceed archive limit
5424
        for ($i = 0; $i < 5; ++$i) {
5425
            $contentDraft = $contentService->createContentDraft($content->contentInfo);
5426
            $contentUpdateStruct = $contentService->newContentUpdateStruct();
5427
            $contentDraft = $contentService->updateContent(
5428
                $contentDraft->versionInfo,
5429
                $contentUpdateStruct
5430
            );
5431
            $contentService->publishVersion($contentDraft->versionInfo);
5432
        }
5433
5434
        $contentService->deleteTranslation($content->contentInfo, 'eng-GB');
5435
5436
        $this->assertTranslationDoesNotExist('eng-GB', $content->id);
5437
    }
5438
5439
    /**
5440
     * Test deleting a Translation which is initial for some Version, updates initialLanguageCode
5441
     * with mainLanguageCode (assuming they are different).
5442
     */
5443
    public function testDeleteTranslationUpdatesInitialLanguageCodeVersion()
5444
    {
5445
        $repository = $this->getRepository();
5446
        $contentService = $repository->getContentService();
5447
5448
        $content = $this->createContentVersion2();
5449
        // create another, copied, version
5450
        $contentDraft = $contentService->updateContent(
5451
            $contentService->createContentDraft($content->contentInfo)->versionInfo,
5452
            $contentService->newContentUpdateStruct()
5453
        );
5454
        $publishedContent = $contentService->publishVersion($contentDraft->versionInfo);
5455
5456
        // remove first version with only one translation as it is not the subject of this test
5457
        $contentService->deleteVersion(
5458
            $contentService->loadVersionInfo($publishedContent->contentInfo, 1)
5459
        );
5460
5461
        // sanity check
5462
        self::assertEquals('eng-US', $content->contentInfo->mainLanguageCode);
5463
        self::assertEquals('eng-US', $content->versionInfo->initialLanguageCode);
5464
5465
        // update mainLanguageCode so it is different than initialLanguageCode for Version
5466
        $contentMetadataUpdateStruct = $contentService->newContentMetadataUpdateStruct();
5467
        $contentMetadataUpdateStruct->mainLanguageCode = 'eng-GB';
5468
        $content = $contentService->updateContentMetadata($publishedContent->contentInfo, $contentMetadataUpdateStruct);
5469
5470
        $contentService->deleteTranslation($content->contentInfo, 'eng-US');
5471
5472
        $this->assertTranslationDoesNotExist('eng-US', $content->id);
5473
    }
5474
5475
    /**
5476
     * Test removal of the specific translation properly updates languages of the URL alias.
5477
     *
5478
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteTranslation
5479
     */
5480
    public function testDeleteTranslationUpdatesUrlAlias()
5481
    {
5482
        $repository = $this->getRepository();
5483
        $contentService = $repository->getContentService();
5484
        $locationService = $repository->getLocationService();
5485
        $urlAliasService = $repository->getURLAliasService();
5486
5487
        $content = $this->createContentVersion2();
5488
        $mainLocation = $locationService->loadLocation($content->contentInfo->mainLocationId);
5489
5490
        // create custom URL alias for Content main Location
5491
        $urlAliasService->createUrlAlias($mainLocation, '/my-custom-url', 'eng-GB');
5492
5493
        // create secondary Location for Content
5494
        $secondaryLocation = $locationService->createLocation(
5495
            $content->contentInfo,
5496
            $locationService->newLocationCreateStruct(2)
5497
        );
5498
5499
        // create custom URL alias for Content secondary Location
5500
        $urlAliasService->createUrlAlias($secondaryLocation, '/my-secondary-url', 'eng-GB');
5501
5502
        // delete Translation
5503
        $contentService->deleteTranslation($content->contentInfo, 'eng-GB');
5504
5505
        foreach ([$mainLocation, $secondaryLocation] as $location) {
5506
            // check auto-generated URL aliases
5507
            foreach ($urlAliasService->listLocationAliases($location, false) as $alias) {
5508
                self::assertNotContains('eng-GB', $alias->languageCodes);
5509
            }
5510
5511
            // check custom URL aliases
5512
            foreach ($urlAliasService->listLocationAliases($location) as $alias) {
5513
                self::assertNotContains('eng-GB', $alias->languageCodes);
5514
            }
5515
        }
5516
    }
5517
5518
    /**
5519
     * Test removal of a main translation throws BadStateException.
5520
     *
5521
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteTranslation
5522
     */
5523
    public function testDeleteTranslationMainLanguageThrowsBadStateException()
5524
    {
5525
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\BadStateException::class);
5526
        $this->expectExceptionMessage('Specified translation is the main translation of the Content Object');
5527
5528
        $repository = $this->getRepository();
5529
        $contentService = $repository->getContentService();
5530
        $content = $this->createContentVersion2();
5531
5532
        // delete first version which has only one translation
5533
        $contentService->deleteVersion($contentService->loadVersionInfo($content->contentInfo, 1));
5534
5535
        // try to delete main translation
5536
        $contentService->deleteTranslation($content->contentInfo, $content->contentInfo->mainLanguageCode);
5537
    }
5538
5539
    /**
5540
     * Test removal of a Translation is possible when some archived Versions have only this Translation.
5541
     *
5542
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteTranslation
5543
     */
5544
    public function testDeleteTranslationDeletesSingleTranslationVersions()
5545
    {
5546
        $repository = $this->getRepository();
5547
        $contentService = $repository->getContentService();
5548
        // content created by the createContentVersion1 method has eng-US translation only.
5549
        $content = $this->createContentVersion1();
5550
5551
        // create new version and add eng-GB translation
5552
        $contentDraft = $contentService->createContentDraft($content->contentInfo);
5553
        $contentUpdateStruct = $contentService->newContentUpdateStruct();
5554
        $contentUpdateStruct->setField('name', 'Awesome Board', 'eng-GB');
5555
        $contentDraft = $contentService->updateContent($contentDraft->versionInfo, $contentUpdateStruct);
5556
        $publishedContent = $contentService->publishVersion($contentDraft->versionInfo);
5557
5558
        // update mainLanguageCode to avoid exception related to that
5559
        $contentMetadataUpdateStruct = $contentService->newContentMetadataUpdateStruct();
5560
        $contentMetadataUpdateStruct->mainLanguageCode = 'eng-GB';
5561
5562
        $content = $contentService->updateContentMetadata($publishedContent->contentInfo, $contentMetadataUpdateStruct);
5563
5564
        $contentService->deleteTranslation($content->contentInfo, 'eng-US');
5565
5566
        $this->assertTranslationDoesNotExist('eng-US', $content->id);
5567
    }
5568
5569
    /**
5570
     * Test removal of the translation by the user who is not allowed to delete a content
5571
     * throws UnauthorizedException.
5572
     *
5573
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteTranslation
5574
     */
5575
    public function testDeleteTranslationThrowsUnauthorizedException()
5576
    {
5577
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\UnauthorizedException::class);
5578
        $this->expectExceptionMessage('User does not have access to \'remove\' \'content\'');
5579
5580
        $repository = $this->getRepository();
5581
        $contentService = $repository->getContentService();
5582
5583
        $content = $this->createContentVersion2();
5584
5585
        // create user that can read/create/edit but cannot delete content
5586
        $this->createRoleWithPolicies('Writer', [
5587
            ['module' => 'content', 'function' => 'read'],
5588
            ['module' => 'content', 'function' => 'versionread'],
5589
            ['module' => 'content', 'function' => 'create'],
5590
            ['module' => 'content', 'function' => 'edit'],
5591
        ]);
5592
        $writerUser = $this->createCustomUserWithLogin(
5593
            'writer',
5594
            '[email protected]',
5595
            'Writers',
5596
            'Writer'
5597
        );
5598
        $repository->getPermissionResolver()->setCurrentUserReference($writerUser);
5599
        $contentService->deleteTranslation($content->contentInfo, 'eng-GB');
5600
    }
5601
5602
    /**
5603
     * Test removal of a non-existent translation throws InvalidArgumentException.
5604
     *
5605
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteTranslation
5606
     */
5607
    public function testDeleteTranslationThrowsInvalidArgumentException()
5608
    {
5609
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\InvalidArgumentException::class);
5610
        $this->expectExceptionMessage('Argument \'$languageCode\' is invalid: ger-DE does not exist in the Content item');
5611
5612
        $repository = $this->getRepository();
5613
        $contentService = $repository->getContentService();
5614
        // content created by the createContentVersion1 method has eng-US translation only.
5615
        $content = $this->createContentVersion1();
5616
        $contentService->deleteTranslation($content->contentInfo, 'ger-DE');
5617
    }
5618
5619
    /**
5620
     * Test deleting a Translation from Draft.
5621
     *
5622
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteTranslationFromDraft
5623
     */
5624
    public function testDeleteTranslationFromDraft()
5625
    {
5626
        $repository = $this->getRepository();
5627
        $contentService = $repository->getContentService();
5628
5629
        $languageCode = 'eng-GB';
5630
        $content = $this->createMultipleLanguageContentVersion2();
5631
        $draft = $contentService->createContentDraft($content->contentInfo);
5632
        $draft = $contentService->deleteTranslationFromDraft($draft->versionInfo, $languageCode);
5633
        $content = $contentService->publishVersion($draft->versionInfo);
5634
5635
        $loadedContent = $contentService->loadContent($content->id);
5636
        self::assertNotContains($languageCode, $loadedContent->versionInfo->languageCodes);
5637
        self::assertEmpty($loadedContent->getFieldsByLanguage($languageCode));
5638
    }
5639
5640
    /**
5641
     * Get values for multilingual field.
5642
     *
5643
     * @return array
5644
     */
5645
    public function providerForDeleteTranslationFromDraftRemovesUrlAliasOnPublishing()
5646
    {
5647
        return [
5648
            [
5649
                ['eng-US' => 'US Name', 'eng-GB' => 'GB Name'],
5650
            ],
5651
            [
5652
                ['eng-US' => 'Same Name', 'eng-GB' => 'Same Name'],
5653
            ],
5654
        ];
5655
    }
5656
5657
    /**
5658
     * Test deleting a Translation from Draft removes previously stored URL aliases for published Content.
5659
     *
5660
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteTranslationFromDraft
5661
     *
5662
     * @dataProvider providerForDeleteTranslationFromDraftRemovesUrlAliasOnPublishing
5663
     *
5664
     * @param string[] $fieldValues translated field values
5665
     *
5666
     * @throws \eZ\Publish\API\Repository\Exceptions\BadStateException
5667
     * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
5668
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
5669
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
5670
     */
5671
    public function testDeleteTranslationFromDraftRemovesUrlAliasOnPublishing(array $fieldValues)
5672
    {
5673
        $repository = $this->getRepository();
5674
        $contentService = $repository->getContentService();
5675
        $locationService = $repository->getLocationService();
5676
        $urlAliasService = $repository->getURLAliasService();
5677
5678
        // set language code to be removed
5679
        $languageCode = 'eng-GB';
5680
        $draft = $this->createMultilingualContentDraft(
5681
            'folder',
5682
            2,
5683
            'eng-US',
5684
            [
5685
                'name' => [
5686
                    'eng-GB' => $fieldValues['eng-GB'],
5687
                    'eng-US' => $fieldValues['eng-US'],
5688
                ],
5689
            ]
5690
        );
5691
        $content = $contentService->publishVersion($draft->versionInfo);
5692
5693
        // create secondary location
5694
        $locationService->createLocation(
5695
            $content->contentInfo,
5696
            $locationService->newLocationCreateStruct(5)
5697
        );
5698
5699
        // sanity check
5700
        $locations = $locationService->loadLocations($content->contentInfo);
5701
        self::assertCount(2, $locations, 'Sanity check: Expected to find 2 Locations');
5702
        foreach ($locations as $location) {
5703
            $urlAliasService->createUrlAlias($location, '/us-custom_' . $location->id, 'eng-US');
5704
            $urlAliasService->createUrlAlias($location, '/gb-custom_' . $location->id, 'eng-GB');
5705
5706
            // check default URL aliases
5707
            $aliases = $urlAliasService->listLocationAliases($location, false, $languageCode);
5708
            self::assertNotEmpty($aliases, 'Sanity check: URL alias for the translation does not exist');
5709
5710
            // check custom URL aliases
5711
            $aliases = $urlAliasService->listLocationAliases($location, true, $languageCode);
5712
            self::assertNotEmpty($aliases, 'Sanity check: Custom URL alias for the translation does not exist');
5713
        }
5714
5715
        // delete translation and publish new version
5716
        $draft = $contentService->createContentDraft($content->contentInfo);
5717
        $draft = $contentService->deleteTranslationFromDraft($draft->versionInfo, $languageCode);
5718
        $contentService->publishVersion($draft->versionInfo);
5719
5720
        // check that aliases does not exist
5721
        foreach ($locations as $location) {
5722
            // check default URL aliases
5723
            $aliases = $urlAliasService->listLocationAliases($location, false, $languageCode);
5724
            self::assertEmpty($aliases, 'URL alias for the deleted translation still exists');
5725
5726
            // check custom URL aliases
5727
            $aliases = $urlAliasService->listLocationAliases($location, true, $languageCode);
5728
            self::assertEmpty($aliases, 'Custom URL alias for the deleted translation still exists');
5729
        }
5730
    }
5731
5732
    /**
5733
     * Test that URL aliases for deleted Translations are properly archived.
5734
     */
5735
    public function testDeleteTranslationFromDraftArchivesUrlAliasOnPublishing()
5736
    {
5737
        $repository = $this->getRepository();
5738
        $contentService = $repository->getContentService();
5739
        $urlAliasService = $repository->getURLAliasService();
5740
5741
        $content = $contentService->publishVersion(
5742
            $this->createMultilingualContentDraft(
5743
                'folder',
5744
                2,
5745
                'eng-US',
5746
                [
5747
                    'name' => [
5748
                        'eng-GB' => 'BritishEnglishContent',
5749
                        'eng-US' => 'AmericanEnglishContent',
5750
                    ],
5751
                ]
5752
            )->versionInfo
5753
        );
5754
5755
        $unrelatedContent = $contentService->publishVersion(
5756
            $this->createMultilingualContentDraft(
5757
                'folder',
5758
                2,
5759
                'eng-US',
5760
                [
5761
                    'name' => [
5762
                        'eng-GB' => 'AnotherBritishContent',
5763
                        'eng-US' => 'AnotherAmericanContent',
5764
                    ],
5765
                ]
5766
            )->versionInfo
5767
        );
5768
5769
        $urlAlias = $urlAliasService->lookup('/BritishEnglishContent');
5770
        self::assertFalse($urlAlias->isHistory);
5771
        self::assertEquals($urlAlias->path, '/BritishEnglishContent');
5772
        self::assertEquals($urlAlias->destination, $content->contentInfo->mainLocationId);
5773
5774
        $draft = $contentService->deleteTranslationFromDraft(
5775
            $contentService->createContentDraft($content->contentInfo)->versionInfo,
5776
            'eng-GB'
5777
        );
5778
        $content = $contentService->publishVersion($draft->versionInfo);
5779
5780
        $urlAlias = $urlAliasService->lookup('/BritishEnglishContent');
5781
        self::assertTrue($urlAlias->isHistory);
5782
        self::assertEquals($urlAlias->path, '/BritishEnglishContent');
5783
        self::assertEquals($urlAlias->destination, $content->contentInfo->mainLocationId);
5784
5785
        $unrelatedUrlAlias = $urlAliasService->lookup('/AnotherBritishContent');
5786
        self::assertFalse($unrelatedUrlAlias->isHistory);
5787
        self::assertEquals($unrelatedUrlAlias->path, '/AnotherBritishContent');
5788
        self::assertEquals($unrelatedUrlAlias->destination, $unrelatedContent->contentInfo->mainLocationId);
5789
    }
5790
5791
    /**
5792
     * Test deleting a Translation from Draft which has single Translation throws BadStateException.
5793
     *
5794
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteTranslationFromDraft
5795
     */
5796
    public function testDeleteTranslationFromDraftThrowsBadStateExceptionOnSingleTranslation()
5797
    {
5798
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\BadStateException::class);
5799
        $this->expectExceptionMessage('Specified Translation is the only one Content Object Version has');
5800
5801
        $repository = $this->getRepository();
5802
        $contentService = $repository->getContentService();
5803
5804
        // create Content with single Translation
5805
        $publishedContent = $contentService->publishVersion(
5806
            $this->createContentDraft(
5807
                'forum',
5808
                2,
5809
                ['name' => 'Eng-US Version name']
5810
            )->versionInfo
5811
        );
5812
5813
        // update mainLanguageCode to avoid exception related to trying to delete main Translation
5814
        $contentMetadataUpdateStruct = $contentService->newContentMetadataUpdateStruct();
5815
        $contentMetadataUpdateStruct->mainLanguageCode = 'eng-GB';
5816
        $publishedContent = $contentService->updateContentMetadata(
5817
            $publishedContent->contentInfo,
5818
            $contentMetadataUpdateStruct
5819
        );
5820
5821
        // create single Translation Version from the first one
5822
        $draft = $contentService->createContentDraft(
5823
            $publishedContent->contentInfo,
5824
            $publishedContent->versionInfo
5825
        );
5826
5827
        // attempt to delete Translation
5828
        $contentService->deleteTranslationFromDraft($draft->versionInfo, 'eng-US');
5829
    }
5830
5831
    /**
5832
     * Test deleting the Main Translation from Draft throws BadStateException.
5833
     *
5834
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteTranslationFromDraft
5835
     */
5836
    public function testDeleteTranslationFromDraftThrowsBadStateExceptionOnMainTranslation()
5837
    {
5838
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\BadStateException::class);
5839
        $this->expectExceptionMessage('Specified Translation is the main Translation of the Content Object');
5840
5841
        $repository = $this->getRepository();
5842
        $contentService = $repository->getContentService();
5843
5844
        $mainLanguageCode = 'eng-US';
5845
        $draft = $this->createMultilingualContentDraft(
5846
            'forum',
5847
            2,
5848
            $mainLanguageCode,
5849
            [
5850
                'name' => [
5851
                    'eng-US' => 'An awesome eng-US forum',
5852
                    'eng-GB' => 'An awesome eng-GB forum',
5853
                ],
5854
            ]
5855
        );
5856
        $contentService->deleteTranslationFromDraft($draft->versionInfo, $mainLanguageCode);
5857
    }
5858
5859
    /**
5860
     * Test deleting the Translation from Published Version throws BadStateException.
5861
     *
5862
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteTranslationFromDraft
5863
     */
5864
    public function testDeleteTranslationFromDraftThrowsBadStateExceptionOnPublishedVersion()
5865
    {
5866
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\BadStateException::class);
5867
        $this->expectExceptionMessage('Version is not a draft');
5868
5869
        $repository = $this->getRepository();
5870
        $contentService = $repository->getContentService();
5871
5872
        $languageCode = 'eng-US';
5873
        $content = $this->createMultipleLanguageContentVersion2();
5874
        $draft = $contentService->createContentDraft($content->contentInfo);
5875
        $publishedContent = $contentService->publishVersion($draft->versionInfo);
5876
        $contentService->deleteTranslationFromDraft($publishedContent->versionInfo, $languageCode);
5877
    }
5878
5879
    /**
5880
     * Test deleting a Translation from Draft throws UnauthorizedException if user cannot edit Content.
5881
     *
5882
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteTranslationFromDraft
5883
     */
5884
    public function testDeleteTranslationFromDraftThrowsUnauthorizedException()
5885
    {
5886
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\UnauthorizedException::class);
5887
        $this->expectExceptionMessage('User does not have access to \'edit\' \'content\'');
5888
5889
        $repository = $this->getRepository();
5890
        $contentService = $repository->getContentService();
5891
5892
        $languageCode = 'eng-GB';
5893
        $content = $this->createMultipleLanguageContentVersion2();
5894
        $draft = $contentService->createContentDraft($content->contentInfo);
5895
5896
        // create user that can read/create/delete but cannot edit or content
5897
        $this->createRoleWithPolicies('Writer', [
5898
            ['module' => 'content', 'function' => 'read'],
5899
            ['module' => 'content', 'function' => 'versionread'],
5900
            ['module' => 'content', 'function' => 'create'],
5901
            ['module' => 'content', 'function' => 'delete'],
5902
        ]);
5903
        $writerUser = $this->createCustomUserWithLogin(
5904
            'user',
5905
            '[email protected]',
5906
            'Writers',
5907
            'Writer'
5908
        );
5909
        $repository->getPermissionResolver()->setCurrentUserReference($writerUser);
5910
5911
        $contentService->deleteTranslationFromDraft($draft->versionInfo, $languageCode);
5912
    }
5913
5914
    /**
5915
     * Test deleting a non-existent Translation from Draft throws InvalidArgumentException.
5916
     *
5917
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteTranslationFromDraft
5918
     */
5919
    public function testDeleteTranslationFromDraftThrowsInvalidArgumentException()
5920
    {
5921
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\InvalidArgumentException::class);
5922
        $this->expectExceptionMessageRegExp('/The Version \\(ContentId=\\d+, VersionNo=\\d+\\) is not translated into ger-DE/');
5923
5924
        $repository = $this->getRepository();
5925
        $contentService = $repository->getContentService();
5926
5927
        $languageCode = 'ger-DE';
5928
        $content = $this->createMultipleLanguageContentVersion2();
5929
        $draft = $contentService->createContentDraft($content->contentInfo);
5930
        $contentService->deleteTranslationFromDraft($draft->versionInfo, $languageCode);
5931
    }
5932
5933
    /**
5934
     * Test loading list of Content items.
5935
     */
5936
    public function testLoadContentListByContentInfo()
5937
    {
5938
        $repository = $this->getRepository();
5939
        $contentService = $repository->getContentService();
5940
        $locationService = $repository->getLocationService();
5941
5942
        $allLocationsCount = $locationService->getAllLocationsCount();
5943
        $contentInfoList = array_map(
5944
            function (Location $location) {
5945
                return $location->contentInfo;
5946
            },
5947
            $locationService->loadAllLocations(0, $allLocationsCount)
5948
        );
5949
5950
        $contentList = $contentService->loadContentListByContentInfo($contentInfoList);
5951
        self::assertCount(count($contentInfoList), $contentList);
5952
        foreach ($contentList as $content) {
5953
            try {
5954
                $loadedContent = $contentService->loadContent($content->id);
5955
                self::assertEquals($loadedContent, $content, "Failed to properly bulk-load Content {$content->id}");
5956
            } catch (NotFoundException $e) {
5957
                self::fail("Failed to load Content {$content->id}: {$e->getMessage()}");
5958
            } catch (UnauthorizedException $e) {
5959
                self::fail("Failed to load Content {$content->id}: {$e->getMessage()}");
5960
            }
5961
        }
5962
    }
5963
5964
    /**
5965
     * Test loading content versions after removing exactly two drafts.
5966
     *
5967
     * @see https://jira.ez.no/browse/EZP-30271
5968
     *
5969
     * @covers \eZ\Publish\Core\Repository\ContentService::deleteVersion
5970
     */
5971
    public function testLoadVersionsAfterDeletingTwoDrafts()
5972
    {
5973
        $repository = $this->getRepository();
5974
        $contentService = $repository->getContentService();
5975
5976
        $content = $this->createFolder(['eng-GB' => 'Foo'], 2);
5977
5978
        // First update and publish
5979
        $modifiedContent = $this->updateFolder($content, ['eng-GB' => 'Foo1']);
5980
        $content = $contentService->publishVersion($modifiedContent->versionInfo);
5981
5982
        // Second update and publish
5983
        $modifiedContent = $this->updateFolder($content, ['eng-GB' => 'Foo2']);
5984
        $content = $contentService->publishVersion($modifiedContent->versionInfo);
5985
5986
        // Create drafts
5987
        $this->updateFolder($content, ['eng-GB' => 'Foo3']);
5988
        $this->updateFolder($content, ['eng-GB' => 'Foo4']);
5989
5990
        $versions = $contentService->loadVersions($content->contentInfo);
5991
5992
        foreach ($versions as $key => $version) {
5993
            if ($version->isDraft()) {
5994
                $contentService->deleteVersion($version);
5995
                unset($versions[$key]);
5996
            }
5997
        }
5998
5999
        $this->assertEquals($versions, $contentService->loadVersions($content->contentInfo));
6000
    }
6001
6002
    /**
6003
     * Tests loading list of content versions of status draft.
6004
     */
6005
    public function testLoadVersionsOfStatusDraft()
6006
    {
6007
        $repository = $this->getRepository();
6008
6009
        $contentService = $repository->getContentService();
6010
6011
        $content = $this->createContentVersion1();
6012
6013
        $contentService->createContentDraft($content->contentInfo);
6014
        $contentService->createContentDraft($content->contentInfo);
6015
        $contentService->createContentDraft($content->contentInfo);
6016
6017
        $versions = $contentService->loadVersions($content->contentInfo, VersionInfo::STATUS_DRAFT);
6018
6019
        $this->assertSame(\count($versions), 3);
6020
    }
6021
6022
    /**
6023
     * Tests loading list of content versions of status archived.
6024
     */
6025
    public function testLoadVersionsOfStatusArchived()
6026
    {
6027
        $repository = $this->getRepository();
6028
6029
        $contentService = $repository->getContentService();
6030
6031
        $content = $this->createContentVersion1();
6032
6033
        $draft1 = $contentService->createContentDraft($content->contentInfo);
6034
        $contentService->publishVersion($draft1->versionInfo);
6035
6036
        $draft2 = $contentService->createContentDraft($content->contentInfo);
6037
        $contentService->publishVersion($draft2->versionInfo);
6038
6039
        $versions = $contentService->loadVersions($content->contentInfo, VersionInfo::STATUS_ARCHIVED);
6040
6041
        $this->assertSame(\count($versions), 2);
6042
    }
6043
6044
    /**
6045
     * Asserts that all aliases defined in $expectedAliasProperties with the
6046
     * given properties are available in $actualAliases and not more.
6047
     *
6048
     * @param array $expectedAliasProperties
6049
     * @param array $actualAliases
6050
     */
6051
    private function assertAliasesCorrect(array $expectedAliasProperties, array $actualAliases)
6052
    {
6053
        foreach ($actualAliases as $actualAlias) {
6054
            if (!isset($expectedAliasProperties[$actualAlias->path])) {
6055
                $this->fail(
6056
                    sprintf(
6057
                        'Alias with path "%s" in languages "%s" not expected.',
6058
                        $actualAlias->path,
6059
                        implode(', ', $actualAlias->languageCodes)
6060
                    )
6061
                );
6062
            }
6063
6064
            foreach ($expectedAliasProperties[$actualAlias->path] as $propertyName => $propertyValue) {
6065
                $this->assertEquals(
6066
                    $propertyValue,
6067
                    $actualAlias->$propertyName,
6068
                    sprintf(
6069
                        'Property $%s incorrect on alias with path "%s" in languages "%s".',
6070
                        $propertyName,
6071
                        $actualAlias->path,
6072
                        implode(', ', $actualAlias->languageCodes)
6073
                    )
6074
                );
6075
            }
6076
6077
            unset($expectedAliasProperties[$actualAlias->path]);
6078
        }
6079
6080
        if (!empty($expectedAliasProperties)) {
6081
            $this->fail(
6082
                sprintf(
6083
                    'Missing expected aliases with paths "%s".',
6084
                    implode('", "', array_keys($expectedAliasProperties))
6085
                )
6086
            );
6087
        }
6088
    }
6089
6090
    /**
6091
     * Asserts that the given fields are equal to the default fields fixture.
6092
     *
6093
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $fields
6094
     */
6095
    private function assertAllFieldsEquals(array $fields)
6096
    {
6097
        $actual = $this->normalizeFields($fields);
6098
        $expected = $this->normalizeFields($this->createFieldsFixture());
6099
6100
        $this->assertEquals($expected, $actual);
6101
    }
6102
6103
    /**
6104
     * Asserts that the given fields are equal to a language filtered set of the
6105
     * default fields fixture.
6106
     *
6107
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $fields
6108
     * @param string $languageCode
6109
     */
6110
    private function assertLocaleFieldsEquals(array $fields, $languageCode)
6111
    {
6112
        $actual = $this->normalizeFields($fields);
6113
6114
        $expected = [];
6115
        foreach ($this->normalizeFields($this->createFieldsFixture()) as $field) {
6116
            if ($field->languageCode !== $languageCode) {
6117
                continue;
6118
            }
6119
            $expected[] = $field;
6120
        }
6121
6122
        $this->assertEquals($expected, $actual);
6123
    }
6124
6125
    /**
6126
     * This method normalizes a set of fields and returns a normalized set.
6127
     *
6128
     * Normalization means it resets the storage specific field id to zero and
6129
     * it sorts the field by their identifier and their language code. In
6130
     * addition, the field value is removed, since this one depends on the
6131
     * specific FieldType, which is tested in a dedicated integration test.
6132
     *
6133
     * @param \eZ\Publish\API\Repository\Values\Content\Field[] $fields
6134
     *
6135
     * @return \eZ\Publish\API\Repository\Values\Content\Field[]
6136
     */
6137
    private function normalizeFields(array $fields)
6138
    {
6139
        $normalized = [];
6140
        foreach ($fields as $field) {
6141
            $normalized[] = new Field(
6142
                [
6143
                    'id' => 0,
6144
                    'value' => ($field->value !== null ? true : null),
6145
                    'languageCode' => $field->languageCode,
6146
                    'fieldDefIdentifier' => $field->fieldDefIdentifier,
6147
                    'fieldTypeIdentifier' => $field->fieldTypeIdentifier,
6148
                ]
6149
            );
6150
        }
6151
        usort(
6152
            $normalized,
6153
            function ($field1, $field2) {
6154
                if (0 === ($return = strcasecmp($field1->fieldDefIdentifier, $field2->fieldDefIdentifier))) {
6155
                    return strcasecmp($field1->languageCode, $field2->languageCode);
6156
                }
6157
6158
                return $return;
6159
            }
6160
        );
6161
6162
        return $normalized;
6163
    }
6164
6165
    /**
6166
     * Returns a filtered set of the default fields fixture.
6167
     *
6168
     * @param string $languageCode
6169
     *
6170
     * @return \eZ\Publish\API\Repository\Values\Content\Field[]
6171
     */
6172
    private function createLocaleFieldsFixture($languageCode)
6173
    {
6174
        $fields = [];
6175
        foreach ($this->createFieldsFixture() as $field) {
6176
            if (null === $field->languageCode || $languageCode === $field->languageCode) {
6177
                $fields[] = $field;
6178
            }
6179
        }
6180
6181
        return $fields;
6182
    }
6183
6184
    /**
6185
     * Asserts that given Content has default ContentStates.
6186
     *
6187
     * @param \eZ\Publish\API\Repository\Values\Content\ContentInfo $contentInfo
6188
     */
6189
    private function assertDefaultContentStates(ContentInfo $contentInfo)
6190
    {
6191
        $repository = $this->getRepository();
6192
        $objectStateService = $repository->getObjectStateService();
6193
6194
        $objectStateGroups = $objectStateService->loadObjectStateGroups();
6195
6196
        foreach ($objectStateGroups as $objectStateGroup) {
6197
            $contentState = $objectStateService->getContentState($contentInfo, $objectStateGroup);
6198
            foreach ($objectStateService->loadObjectStates($objectStateGroup) as $objectState) {
6199
                // Only check the first object state which is the default one.
6200
                $this->assertEquals(
6201
                    $objectState,
6202
                    $contentState
6203
                );
6204
                break;
6205
            }
6206
        }
6207
    }
6208
6209
    /**
6210
     * Assert that given Content has no references to a translation specified by the $languageCode.
6211
     *
6212
     * @param string $languageCode
6213
     * @param int $contentId
6214
     */
6215
    private function assertTranslationDoesNotExist($languageCode, $contentId)
6216
    {
6217
        $repository = $this->getRepository();
6218
        $contentService = $repository->getContentService();
6219
6220
        $content = $contentService->loadContent($contentId);
6221
6222
        foreach ($content->fields as $fieldIdentifier => $field) {
6223
            /** @var array $field */
6224
            self::assertArrayNotHasKey($languageCode, $field);
6225
            self::assertNotEquals($languageCode, $content->contentInfo->mainLanguageCode);
6226
            self::assertArrayNotHasKey($languageCode, $content->versionInfo->getNames());
6227
            self::assertNotEquals($languageCode, $content->versionInfo->initialLanguageCode);
6228
            self::assertNotContains($languageCode, $content->versionInfo->languageCodes);
6229
        }
6230
        foreach ($contentService->loadVersions($content->contentInfo) as $versionInfo) {
6231
            self::assertArrayNotHasKey($languageCode, $versionInfo->getNames());
6232
            self::assertNotEquals($languageCode, $versionInfo->contentInfo->mainLanguageCode);
6233
            self::assertNotEquals($languageCode, $versionInfo->initialLanguageCode);
6234
            self::assertNotContains($languageCode, $versionInfo->languageCodes);
6235
        }
6236
    }
6237
6238
    /**
6239
     * Returns the default fixture of fields used in most tests.
6240
     *
6241
     * @return \eZ\Publish\API\Repository\Values\Content\Field[]
6242
     */
6243
    private function createFieldsFixture()
6244
    {
6245
        return [
6246
            new Field(
6247
                [
6248
                    'id' => 0,
6249
                    'value' => 'Foo',
6250
                    'languageCode' => 'eng-US',
6251
                    'fieldDefIdentifier' => 'description',
6252
                    'fieldTypeIdentifier' => 'ezrichtext',
6253
                ]
6254
            ),
6255
            new Field(
6256
                [
6257
                    'id' => 0,
6258
                    'value' => 'Bar',
6259
                    'languageCode' => 'eng-GB',
6260
                    'fieldDefIdentifier' => 'description',
6261
                    'fieldTypeIdentifier' => 'ezrichtext',
6262
                ]
6263
            ),
6264
            new Field(
6265
                [
6266
                    'id' => 0,
6267
                    'value' => 'An awesome multi-lang forum²',
6268
                    'languageCode' => 'eng-US',
6269
                    'fieldDefIdentifier' => 'name',
6270
                    'fieldTypeIdentifier' => 'ezstring',
6271
                ]
6272
            ),
6273
            new Field(
6274
                [
6275
                    'id' => 0,
6276
                    'value' => 'An awesome multi-lang forum²³',
6277
                    'languageCode' => 'eng-GB',
6278
                    'fieldDefIdentifier' => 'name',
6279
                    'fieldTypeIdentifier' => 'ezstring',
6280
                ]
6281
            ),
6282
        ];
6283
    }
6284
6285
    /**
6286
     * Gets expected property values for the "Media" ContentInfo ValueObject.
6287
     *
6288
     * @return array
6289
     */
6290
    private function getExpectedMediaContentInfoProperties()
6291
    {
6292
        return [
6293
            'id' => 41,
6294
            'contentTypeId' => 1,
6295
            'name' => 'Media',
6296
            'sectionId' => 3,
6297
            'currentVersionNo' => 1,
6298
            'published' => true,
6299
            'ownerId' => 14,
6300
            'modificationDate' => $this->createDateTime(1060695457),
6301
            'publishedDate' => $this->createDateTime(1060695457),
6302
            'alwaysAvailable' => 1,
6303
            'remoteId' => 'a6e35cbcb7cd6ae4b691f3eee30cd262',
6304
            'mainLanguageCode' => 'eng-US',
6305
            'mainLocationId' => 43,
6306
            'status' => ContentInfo::STATUS_PUBLISHED,
6307
        ];
6308
    }
6309
6310
    /**
6311
     * @covers \eZ\Publish\API\Repository\ContentService::hideContent
6312
     *
6313
     * @throws \eZ\Publish\API\Repository\Exceptions\ForbiddenException
6314
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
6315
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
6316
     */
6317
    public function testHideContent(): void
6318
    {
6319
        $repository = $this->getRepository();
6320
        $contentTypeService = $repository->getContentTypeService();
6321
        $contentService = $repository->getContentService();
6322
        $locationService = $repository->getLocationService();
6323
6324
        $locationCreateStructs = array_map(
6325
            function (Location $parentLocation) use ($locationService) {
6326
                return $locationService->newLocationCreateStruct($parentLocation->id);
6327
            },
6328
            $this->createParentLocationsForHideReveal($locationService, 2)
6329
        );
6330
6331
        $contentType = $contentTypeService->loadContentTypeByIdentifier('folder');
6332
6333
        $contentCreate = $contentService->newContentCreateStruct($contentType, 'eng-US');
6334
        $contentCreate->setField('name', 'Folder to hide');
6335
6336
        $content = $contentService->createContent(
6337
            $contentCreate,
6338
            $locationCreateStructs
6339
        );
6340
6341
        $publishedContent = $contentService->publishVersion($content->versionInfo);
6342
        $locations = $locationService->loadLocations($publishedContent->contentInfo);
6343
6344
        // Sanity check
6345
        $this->assertCount(3, $locations);
6346
        $this->assertCount(0, $this->filterHiddenLocations($locations));
6347
6348
        /* BEGIN: Use Case */
6349
        $contentService->hideContent($publishedContent->contentInfo);
6350
        /* END: Use Case */
6351
6352
        $locations = $locationService->loadLocations($publishedContent->contentInfo);
6353
        $this->assertCount(3, $locations);
6354
        $this->assertCount(3, $this->filterHiddenLocations($locations));
6355
    }
6356
6357
    /**
6358
     * @covers \eZ\Publish\API\Repository\ContentService::revealContent
6359
     *
6360
     * @throws \eZ\Publish\API\Repository\Exceptions\ForbiddenException
6361
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
6362
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
6363
     */
6364
    public function testRevealContent()
6365
    {
6366
        $repository = $this->getRepository();
6367
        $contentTypeService = $repository->getContentTypeService();
6368
        $contentService = $repository->getContentService();
6369
        $locationService = $repository->getLocationService();
6370
6371
        $locationCreateStructs = array_map(
6372
            function (Location $parentLocation) use ($locationService) {
6373
                return $locationService->newLocationCreateStruct($parentLocation->id);
6374
            },
6375
            $this->createParentLocationsForHideReveal($locationService, 2)
6376
        );
6377
6378
        $contentType = $contentTypeService->loadContentTypeByIdentifier('folder');
6379
6380
        $contentCreate = $contentService->newContentCreateStruct($contentType, 'eng-US');
6381
        $contentCreate->setField('name', 'Folder to hide');
6382
6383
        $locationCreateStructs[0]->hidden = true;
6384
6385
        $content = $contentService->createContent(
6386
            $contentCreate,
6387
            $locationCreateStructs
6388
        );
6389
6390
        $publishedContent = $contentService->publishVersion($content->versionInfo);
6391
        $locations = $locationService->loadLocations($publishedContent->contentInfo);
6392
6393
        // Sanity check
6394
        $hiddenLocations = $this->filterHiddenLocations($locations);
6395
        $this->assertCount(3, $locations);
6396
        $this->assertCount(1, $hiddenLocations);
6397
6398
        // BEGIN: Use Case
6399
        $contentService->hideContent($publishedContent->contentInfo);
6400
        $this->assertCount(
6401
            3,
6402
            $this->filterHiddenLocations(
6403
                $locationService->loadLocations($publishedContent->contentInfo)
6404
            )
6405
        );
6406
6407
        $contentService->revealContent($publishedContent->contentInfo);
6408
        // END: Use Case
6409
6410
        $locations = $locationService->loadLocations($publishedContent->contentInfo);
6411
        $hiddenLocationsAfterReveal = $this->filterHiddenLocations($locations);
6412
        $this->assertCount(3, $locations);
6413
        $this->assertCount(1, $hiddenLocationsAfterReveal);
6414
        $this->assertEquals($hiddenLocations, $hiddenLocationsAfterReveal);
6415
    }
6416
6417
    /**
6418
     * @depends testRevealContent
6419
     */
6420
    public function testRevealContentWithHiddenParent()
6421
    {
6422
        $repository = $this->getRepository();
6423
6424
        $contentTypeService = $repository->getContentTypeService();
6425
        $contentService = $repository->getContentService();
6426
        $locationService = $repository->getLocationService();
6427
6428
        $contentType = $contentTypeService->loadContentTypeByIdentifier('folder');
6429
6430
        $contentNames = [
6431
            'Parent Content',
6432
            'Child (Nesting 1)',
6433
            'Child (Nesting 2)',
6434
            'Child (Nesting 3)',
6435
            'Child (Nesting 4)',
6436
        ];
6437
6438
        $parentLocation = $locationService->newLocationCreateStruct(
6439
            $this->generateId('location', 2)
6440
        );
6441
6442
        /** @var Content[] $contents */
6443
        $contents = [];
6444
6445
        foreach ($contentNames as $contentName) {
6446
            $contentCreate = $contentService->newContentCreateStruct($contentType, 'eng-US');
6447
            $contentCreate->setField('name', $contentName);
6448
6449
            $content = $contentService->createContent($contentCreate, [$parentLocation]);
6450
            $contents[] = $publishedContent = $contentService->publishVersion($content->versionInfo);
6451
6452
            $parentLocation = $locationService->newLocationCreateStruct(
6453
                $this->generateId('location', $publishedContent->contentInfo->mainLocationId)
6454
            );
6455
        }
6456
6457
        $contentService->hideContent($contents[0]->contentInfo);
6458
        $contentService->hideContent($contents[2]->contentInfo);
6459
        $contentService->revealContent($contents[2]->contentInfo);
6460
6461
        $parentContent = $contentService->loadContent($contents[0]->id);
6462
        $parentLocation = $locationService->loadLocation($parentContent->contentInfo->mainLocationId);
6463
        $parentSublocations = $locationService->loadLocationList([
6464
            $contents[1]->contentInfo->mainLocationId,
6465
            $contents[2]->contentInfo->mainLocationId,
6466
            $contents[3]->contentInfo->mainLocationId,
6467
            $contents[4]->contentInfo->mainLocationId,
6468
        ]);
6469
6470
        // Parent remains invisible
6471
        self::assertTrue($parentLocation->invisible);
6472
6473
        // All parent sublocations remain invisible as well
6474
        foreach ($parentSublocations as $parentSublocation) {
6475
            self::assertTrue($parentSublocation->invisible);
6476
        }
6477
    }
6478
6479
    /**
6480
     * @depends testRevealContent
6481
     */
6482
    public function testRevealContentWithHiddenChildren()
6483
    {
6484
        $repository = $this->getRepository();
6485
6486
        $contentTypeService = $repository->getContentTypeService();
6487
        $contentService = $repository->getContentService();
6488
        $locationService = $repository->getLocationService();
6489
6490
        $contentType = $contentTypeService->loadContentTypeByIdentifier('folder');
6491
6492
        $contentNames = [
6493
            'Parent Content',
6494
            'Child (Nesting 1)',
6495
            'Child (Nesting 2)',
6496
            'Child (Nesting 3)',
6497
            'Child (Nesting 4)',
6498
        ];
6499
6500
        $parentLocation = $locationService->newLocationCreateStruct(
6501
            $this->generateId('location', 2)
6502
        );
6503
6504
        /** @var Content[] $contents */
6505
        $contents = [];
6506
6507
        foreach ($contentNames as $contentName) {
6508
            $contentCreate = $contentService->newContentCreateStruct($contentType, 'eng-US');
6509
            $contentCreate->setField('name', $contentName);
6510
6511
            $content = $contentService->createContent($contentCreate, [$parentLocation]);
6512
            $contents[] = $publishedContent = $contentService->publishVersion($content->versionInfo);
6513
6514
            $parentLocation = $locationService->newLocationCreateStruct(
6515
                $this->generateId('location', $publishedContent->contentInfo->mainLocationId)
6516
            );
6517
        }
6518
6519
        $contentService->hideContent($contents[0]->contentInfo);
6520
        $contentService->hideContent($contents[2]->contentInfo);
6521
        $contentService->revealContent($contents[0]->contentInfo);
6522
6523
        $directChildContent = $contentService->loadContent($contents[1]->id);
6524
        $directChildLocation = $locationService->loadLocation($directChildContent->contentInfo->mainLocationId);
6525
6526
        $childContent = $contentService->loadContent($contents[2]->id);
6527
        $childLocation = $locationService->loadLocation($childContent->contentInfo->mainLocationId);
6528
        $childSublocations = $locationService->loadLocationList([
6529
            $contents[3]->contentInfo->mainLocationId,
6530
            $contents[4]->contentInfo->mainLocationId,
6531
        ]);
6532
6533
        // Direct child content is not hidden
6534
        self::assertFalse($directChildContent->contentInfo->isHidden);
6535
6536
        // Direct child content location is still invisible
6537
        self::assertFalse($directChildLocation->invisible);
6538
6539
        // Child content is still hidden
6540
        self::assertTrue($childContent->contentInfo->isHidden);
6541
6542
        // Child content location is still invisible
6543
        self::assertTrue($childLocation->invisible);
6544
6545
        // All childs sublocations remain invisible as well
6546
        foreach ($childSublocations as $childSublocation) {
6547
            self::assertTrue($childSublocation->invisible);
6548
        }
6549
    }
6550
6551
    public function testHideContentWithParentLocation()
6552
    {
6553
        $repository = $this->getRepository();
6554
        $contentTypeService = $repository->getContentTypeService();
6555
6556
        $contentType = $contentTypeService->loadContentTypeByIdentifier('folder');
6557
6558
        $contentService = $repository->getContentService();
6559
        $locationService = $repository->getLocationService();
6560
6561
        $contentCreate = $contentService->newContentCreateStruct($contentType, 'eng-US');
6562
        $contentCreate->setField('name', 'Parent');
6563
6564
        $content = $contentService->createContent(
6565
            $contentCreate,
6566
            [
6567
                $locationService->newLocationCreateStruct(
6568
                    $this->generateId('location', 2)
6569
                ),
6570
            ]
6571
        );
6572
6573
        $publishedContent = $contentService->publishVersion($content->versionInfo);
6574
6575
        /* BEGIN: Use Case */
6576
        $contentService->hideContent($publishedContent->contentInfo);
6577
        /* END: Use Case */
6578
6579
        $locations = $locationService->loadLocations($publishedContent->contentInfo);
6580
6581
        $childContentCreate = $contentService->newContentCreateStruct($contentType, 'eng-US');
6582
        $childContentCreate->setField('name', 'Child');
6583
6584
        $childContent = $contentService->createContent(
6585
            $childContentCreate,
6586
            [
6587
                $locationService->newLocationCreateStruct(
6588
                    $locations[0]->id
6589
                ),
6590
            ]
6591
        );
6592
6593
        $publishedChildContent = $contentService->publishVersion($childContent->versionInfo);
6594
6595
        $childLocations = $locationService->loadLocations($publishedChildContent->contentInfo);
6596
6597
        $this->assertTrue($locations[0]->hidden);
6598
        $this->assertTrue($locations[0]->invisible);
6599
6600
        $this->assertFalse($childLocations[0]->hidden);
6601
        $this->assertTrue($childLocations[0]->invisible);
6602
    }
6603
6604
    public function testChangeContentName()
6605
    {
6606
        $repository = $this->getRepository();
6607
6608
        $contentService = $repository->getContentService();
6609
        $contentDraft = $this->createContentDraft(
6610
            'folder',
6611
            $this->generateId('location', 2),
6612
            [
6613
                'name' => 'Marco',
6614
            ]
6615
        );
6616
6617
        $publishedContent = $contentService->publishVersion($contentDraft->versionInfo);
6618
        $contentMetadataUpdateStruct = new ContentMetadataUpdateStruct([
6619
            'name' => 'Polo',
6620
        ]);
6621
        $contentService->updateContentMetadata($publishedContent->contentInfo, $contentMetadataUpdateStruct);
6622
6623
        $updatedContent = $contentService->loadContent($publishedContent->id);
6624
6625
        $this->assertEquals('Marco', $publishedContent->contentInfo->name);
6626
        $this->assertEquals('Polo', $updatedContent->contentInfo->name);
6627
    }
6628
6629
    public function testCopyTranslationsFromPublishedToDraft()
6630
    {
6631
        $repository = $this->getRepository();
6632
6633
        $contentService = $repository->getContentService();
6634
6635
        $contentDraft = $this->createContentDraft(
6636
            'folder',
6637
            $this->generateId('location', 2),
6638
            [
6639
                'name' => 'Folder US',
6640
            ]
6641
        );
6642
6643
        $publishedContent = $contentService->publishVersion($contentDraft->versionInfo);
6644
6645
        $deDraft = $contentService->createContentDraft($publishedContent->contentInfo);
6646
6647
        $contentUpdateStruct = new ContentUpdateStruct([
6648
            'initialLanguageCode' => 'ger-DE',
6649
            'fields' => $contentDraft->getFields(),
6650
        ]);
6651
6652
        $contentUpdateStruct->setField('name', 'Folder GER', 'ger-DE');
6653
6654
        $deContent = $contentService->updateContent($deDraft->versionInfo, $contentUpdateStruct);
6655
6656
        $updatedContent = $contentService->loadContent($deContent->id, null, $deContent->versionInfo->versionNo);
6657
        $this->assertEquals(
6658
            [
6659
                'eng-US' => 'Folder US',
6660
                'ger-DE' => 'Folder GER',
6661
            ],
6662
            $updatedContent->fields['name']
6663
        );
6664
6665
        $gbDraft = $contentService->createContentDraft($publishedContent->contentInfo);
6666
6667
        $contentUpdateStruct = new ContentUpdateStruct([
6668
            'initialLanguageCode' => 'eng-GB',
6669
            'fields' => $contentDraft->getFields(),
6670
        ]);
6671
6672
        $contentUpdateStruct->setField('name', 'Folder GB', 'eng-GB');
6673
6674
        $gbContent = $contentService->updateContent($gbDraft->versionInfo, $contentUpdateStruct);
6675
        $contentService->publishVersion($gbDraft->versionInfo);
6676
        $updatedContent = $contentService->loadContent($gbContent->id, null, $gbContent->versionInfo->versionNo);
6677
        $this->assertEquals(
6678
            [
6679
                'eng-US' => 'Folder US',
6680
                'eng-GB' => 'Folder GB',
6681
            ],
6682
            $updatedContent->fields['name']
6683
        );
6684
6685
        $dePublished = $contentService->publishVersion($deDraft->versionInfo);
6686
        $this->assertEquals(
6687
            [
6688
                'eng-US' => 'Folder US',
6689
                'ger-DE' => 'Folder GER',
6690
                'eng-GB' => 'Folder GB',
6691
            ],
6692
            $dePublished->fields['name']
6693
        );
6694
    }
6695
6696
    /**
6697
     * Create structure of parent folders with Locations to be used for Content hide/reveal tests.
6698
     *
6699
     * @param \eZ\Publish\API\Repository\LocationService $locationService
6700
     * @param int $parentLocationId
6701
     *
6702
     * @return \eZ\Publish\API\Repository\Values\Content\Location[] A list of Locations aimed to be parents
6703
     *
6704
     * @throws \eZ\Publish\API\Repository\Exceptions\ForbiddenException
6705
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
6706
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
6707
     */
6708
    private function createParentLocationsForHideReveal(LocationService $locationService, int $parentLocationId): array
6709
    {
6710
        $parentFoldersLocationsIds = [
6711
            $this->createFolder(['eng-US' => 'P1'], $parentLocationId)->contentInfo->mainLocationId,
6712
            $this->createFolder(['eng-US' => 'P2'], $parentLocationId)->contentInfo->mainLocationId,
6713
            $this->createFolder(['eng-US' => 'P3'], $parentLocationId)->contentInfo->mainLocationId,
6714
        ];
6715
6716
        return array_values($locationService->loadLocationList($parentFoldersLocationsIds));
6717
    }
6718
6719
    /**
6720
     * Filter Locations list by hidden only.
6721
     *
6722
     * @param \eZ\Publish\API\Repository\Values\Content\Location[] $locations
6723
     *
6724
     * @return array
6725
     */
6726
    private function filterHiddenLocations(array $locations): array
6727
    {
6728
        return array_values(
6729
            array_filter(
6730
                $locations,
6731
                function (Location $location) {
6732
                    return $location->hidden;
6733
                }
6734
            )
6735
        );
6736
    }
6737
6738
    public function testPublishVersionWithSelectedLanguages()
6739
    {
6740
        $repository = $this->getRepository();
6741
6742
        $contentService = $repository->getContentService();
6743
6744
        $publishedContent = $this->createFolder(
6745
            [
6746
                'eng-US' => 'Published US',
6747
                'ger-DE' => 'Published DE',
6748
            ],
6749
            $this->generateId('location', 2)
6750
        );
6751
6752
        $draft = $contentService->createContentDraft($publishedContent->contentInfo);
6753
        $contentUpdateStruct = new ContentUpdateStruct([
6754
            'initialLanguageCode' => 'eng-US',
6755
        ]);
6756
        $contentUpdateStruct->setField('name', 'Draft 1 US', 'eng-US');
6757
        $contentUpdateStruct->setField('name', 'Draft 1 DE', 'ger-DE');
6758
6759
        $contentService->updateContent($draft->versionInfo, $contentUpdateStruct);
6760
        $contentService->publishVersion($draft->versionInfo, ['ger-DE']);
6761
        $content = $contentService->loadContent($draft->contentInfo->id);
6762
6763
        $this->assertEquals(
6764
            [
6765
                'eng-US' => 'Published US',
6766
                'ger-DE' => 'Draft 1 DE',
6767
            ],
6768
            $content->fields['name']
6769
        );
6770
    }
6771
6772
    public function testCreateContentWithRomanianSpecialCharsInTitle()
6773
    {
6774
        $repository = $this->getRepository();
6775
6776
        $baseName = 'ȘșțȚdfdf';
6777
        $expectedPath = '/SstTdfdf';
6778
6779
        $this->createFolder(['eng-US' => $baseName], 2);
6780
6781
        $urlAliasService = $repository->getURLAliasService();
6782
        $urlAlias = $urlAliasService->lookup($expectedPath);
6783
        $this->assertSame($expectedPath, $urlAlias->path);
6784
    }
6785
}
6786