Skip to content

Commit 29489e4

Browse files
authored
IBX-7346: Reindexed reverse-related content after deleting source content (#396)
1 parent 4abba92 commit 29489e4

File tree

6 files changed

+174
-62
lines changed

6 files changed

+174
-62
lines changed

eZ/Publish/API/Repository/Values/Content/Trash/TrashItemDeleteResult.php

+3
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,7 @@ class TrashItemDeleteResult extends ValueObject
2424
* @var bool
2525
*/
2626
public $contentRemoved = false;
27+
28+
/** @var array<int> */
29+
public $reverseRelationContentIds = [];
2730
}

eZ/Publish/Core/Persistence/Legacy/Content/Location/Trash/Handler.php

+3
Original file line numberDiff line numberDiff line change
@@ -246,11 +246,14 @@ protected function delete(Trashed $trashItem)
246246
$result->trashItemId = $trashItem->id;
247247
$result->contentId = $trashItem->contentId;
248248

249+
$reverseRelations = $this->contentHandler->loadReverseRelations($trashItem->contentId);
250+
249251
$this->locationGateway->removeElementFromTrash($trashItem->id);
250252

251253
if ($this->locationGateway->countLocationsByContentId($trashItem->contentId) < 1) {
252254
$this->contentHandler->deleteContent($trashItem->contentId);
253255
$result->contentRemoved = true;
256+
$result->reverseRelationContentIds = array_column($reverseRelations, 'sourceContentId');
254257
}
255258

256259
return $result;

eZ/Publish/Core/Persistence/Legacy/Tests/Content/Location/TrashHandlerTest.php

+58-52
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,7 @@ public function testLoadTrashItem()
329329
/**
330330
* @covers \eZ\Publish\Core\Persistence\Legacy\Content\Location\Trash\Handler::emptyTrash
331331
*/
332-
public function testEmptyTrash()
332+
public function testEmptyTrash(): void
333333
{
334334
$handler = $this->getTrashHandler();
335335

@@ -354,48 +354,51 @@ public function testEmptyTrash()
354354
$iLocation = 0;
355355

356356
$this->locationGateway
357-
->expects($this->at($i++))
357+
->expects(self::at($i++))
358358
->method('countTrashed')
359359
->willReturn(2);
360360

361361
$this->locationGateway
362-
->expects($this->at($i++))
362+
->expects(self::at($i++))
363363
->method('listTrashed')
364-
->will(
365-
$this->returnValue($expectedTrashed)
366-
);
364+
->willReturn($expectedTrashed);
367365

368366
$trashedItemIds = [];
369367
$trashedContentIds = [];
370368

371369
foreach ($expectedTrashed as $trashedElement) {
372370
$this->locationMapper
373-
->expects($this->at($iLocation++))
371+
->expects(self::at($iLocation++))
374372
->method('createLocationFromRow')
375-
->will(
376-
$this->returnValue(
377-
new Trashed(
378-
[
379-
'id' => $trashedElement['node_id'],
380-
'contentId' => $trashedElement['contentobject_id'],
381-
'pathString' => $trashedElement['path_string'],
382-
]
383-
)
373+
->willReturn(
374+
new Trashed(
375+
[
376+
'id' => $trashedElement['node_id'],
377+
'contentId' => $trashedElement['contentobject_id'],
378+
'pathString' => $trashedElement['path_string'],
379+
]
384380
)
385381
);
382+
383+
$this->contentHandler
384+
->expects(self::at($iContent++))
385+
->method('loadReverseRelations')
386+
->with($trashedElement['contentobject_id'])
387+
->willReturn([]);
388+
386389
$this->locationGateway
387-
->expects($this->at($i++))
390+
->expects(self::at($i++))
388391
->method('removeElementFromTrash')
389392
->with($trashedElement['node_id']);
390393

391394
$this->locationGateway
392-
->expects($this->at($i++))
395+
->expects(self::at($i++))
393396
->method('countLocationsByContentId')
394397
->with($trashedElement['contentobject_id'])
395-
->will($this->returnValue(0));
398+
->willReturn(0);
396399

397400
$this->contentHandler
398-
->expects($this->at($iContent++))
401+
->expects(self::at($iContent++))
399402
->method('deleteContent')
400403
->with($trashedElement['contentobject_id']);
401404

@@ -405,75 +408,78 @@ public function testEmptyTrash()
405408

406409
$returnValue = $handler->emptyTrash();
407410

408-
$this->assertInstanceOf(TrashItemDeleteResultList::class, $returnValue);
411+
self::assertInstanceOf(TrashItemDeleteResultList::class, $returnValue);
409412

410413
foreach ($returnValue->items as $key => $trashItemDeleteResult) {
411-
$this->assertEquals($trashItemDeleteResult->trashItemId, $trashedItemIds[$key]);
412-
$this->assertEquals($trashItemDeleteResult->contentId, $trashedContentIds[$key]);
413-
$this->assertTrue($trashItemDeleteResult->contentRemoved);
414+
self::assertEquals($trashItemDeleteResult->trashItemId, $trashedItemIds[$key]);
415+
self::assertEquals($trashItemDeleteResult->contentId, $trashedContentIds[$key]);
416+
self::assertTrue($trashItemDeleteResult->contentRemoved);
414417
}
415418
}
416419

417420
/**
418421
* @covers \eZ\Publish\Core\Persistence\Legacy\Content\Location\Trash\Handler::deleteTrashItem
419422
*/
420-
public function testDeleteTrashItemNoMoreLocations()
423+
public function testDeleteTrashItemNoMoreLocations(): void
421424
{
422425
$handler = $this->getTrashHandler();
423426

424427
$trashItemId = 69;
425428
$contentId = 67;
429+
426430
$this->locationGateway
427-
->expects($this->once())
431+
->expects(self::once())
428432
->method('loadTrashByLocation')
429433
->with($trashItemId)
430-
->will(
431-
$this->returnValue(
432-
[
433-
'node_id' => $trashItemId,
434-
'contentobject_id' => $contentId,
435-
'path_string' => '/1/2/69',
436-
]
437-
)
434+
->willReturn(
435+
[
436+
'node_id' => $trashItemId,
437+
'contentobject_id' => $contentId,
438+
'path_string' => '/1/2/69',
439+
]
438440
);
439441

440442
$this->locationMapper
441-
->expects($this->once())
443+
->expects(self::once())
442444
->method('createLocationFromRow')
443-
->will(
444-
$this->returnValue(
445-
new Trashed(
446-
[
447-
'id' => $trashItemId,
448-
'contentId' => $contentId,
449-
'pathString' => '/1/2/69',
450-
]
451-
)
445+
->willReturn(
446+
new Trashed(
447+
[
448+
'id' => $trashItemId,
449+
'contentId' => $contentId,
450+
'pathString' => '/1/2/69',
451+
]
452452
)
453453
);
454454

455+
$this->contentHandler
456+
->expects(self::once())
457+
->method('loadReverseRelations')
458+
->with($contentId)
459+
->willReturn([]);
460+
455461
$this->locationGateway
456-
->expects($this->once())
462+
->expects(self::once())
457463
->method('removeElementFromTrash')
458464
->with($trashItemId);
459465

460466
$this->locationGateway
461-
->expects($this->once())
467+
->expects(self::once())
462468
->method('countLocationsByContentId')
463469
->with($contentId)
464-
->will($this->returnValue(0));
470+
->willReturn(0);
465471

466472
$this->contentHandler
467-
->expects($this->once())
473+
->expects(self::once())
468474
->method('deleteContent')
469475
->with($contentId);
470476

471477
$trashItemDeleteResult = $handler->deleteTrashItem($trashItemId);
472478

473-
$this->assertInstanceOf(TrashItemDeleteResult::class, $trashItemDeleteResult);
474-
$this->assertEquals($trashItemId, $trashItemDeleteResult->trashItemId);
475-
$this->assertEquals($contentId, $trashItemDeleteResult->contentId);
476-
$this->assertTrue($trashItemDeleteResult->contentRemoved);
479+
self::assertInstanceOf(TrashItemDeleteResult::class, $trashItemDeleteResult);
480+
self::assertEquals($trashItemId, $trashItemDeleteResult->trashItemId);
481+
self::assertEquals($contentId, $trashItemDeleteResult->contentId);
482+
self::assertTrue($trashItemDeleteResult->contentRemoved);
477483
}
478484

479485
/**

eZ/Publish/Core/Search/Common/EventSubscriber/TrashEventSubscriber.php

+33
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
*/
77
namespace eZ\Publish\Core\Search\Common\EventSubscriber;
88

9+
use eZ\Publish\API\Repository\Events\Trash\DeleteTrashItemEvent;
10+
use eZ\Publish\API\Repository\Events\Trash\EmptyTrashEvent;
911
use eZ\Publish\API\Repository\Events\Trash\RecoverEvent;
1012
use eZ\Publish\API\Repository\Events\Trash\TrashEvent;
1113
use eZ\Publish\API\Repository\Values\Content\TrashItem;
@@ -18,6 +20,8 @@ public static function getSubscribedEvents(): array
1820
return [
1921
RecoverEvent::class => 'onRecover',
2022
TrashEvent::class => 'onTrash',
23+
DeleteTrashItemEvent::class => 'onDeleteTrashItem',
24+
EmptyTrashEvent::class => 'onEmptyTrashEvent',
2125
];
2226
}
2327

@@ -39,4 +43,33 @@ public function onTrash(TrashEvent $event)
3943
$event->getLocation()->contentId
4044
);
4145
}
46+
47+
public function onDeleteTrashItem(DeleteTrashItemEvent $event): void
48+
{
49+
$contentHandler = $this->persistenceHandler->contentHandler();
50+
51+
$reverseRelationContentIds = $event->getResult()->reverseRelationContentIds;
52+
foreach ($reverseRelationContentIds as $contentId) {
53+
$persistenceContent = $contentHandler->load($contentId);
54+
55+
$this->searchHandler->indexContent($persistenceContent);
56+
}
57+
}
58+
59+
public function onEmptyTrashEvent(EmptyTrashEvent $event): void
60+
{
61+
$contentHandler = $this->persistenceHandler->contentHandler();
62+
63+
$results = $event->getResultList()->getIterator();
64+
65+
/** @var \eZ\Publish\API\Repository\Values\Content\Trash\TrashItemDeleteResult $result */
66+
foreach ($results as $result) {
67+
$reverseRelationContentIds = $result->reverseRelationContentIds;
68+
foreach ($reverseRelationContentIds as $contentId) {
69+
$persistenceContent = $contentHandler->load($contentId);
70+
71+
$this->searchHandler->indexContent($persistenceContent);
72+
}
73+
}
74+
}
4275
}

phpstan-baseline.neon

-10
Original file line numberDiff line numberDiff line change
@@ -280,11 +280,6 @@ parameters:
280280
count: 3
281281
path: eZ/Publish/API/Repository/Tests/SearchServiceTranslationLanguageFallbackTest.php
282282

283-
-
284-
message: "#^Undefined variable\\: \\$loader$#"
285-
count: 3
286-
path: eZ/Publish/API/Repository/Tests/SetupFactory/Legacy.php
287-
288283
-
289284
message: "#^Method eZ\\\\Publish\\\\API\\\\Repository\\\\Tests\\\\URLWildcardServiceAuthorizationTest\\:\\:testCreateThrowsUnauthorizedException\\(\\) should return eZ\\\\Publish\\\\API\\\\Repository\\\\Values\\\\Content\\\\URLWildcard but return statement is missing\\.$#"
290285
count: 1
@@ -505,11 +500,6 @@ parameters:
505500
count: 1
506501
path: eZ/Publish/Core/Persistence/Legacy/Content/Type/Handler.php
507502

508-
-
509-
message: "#^Undefined variable\\: \\$loader$#"
510-
count: 2
511-
path: eZ/Publish/Core/Persistence/Legacy/Tests/HandlerTest.php
512-
513503
-
514504
message: "#^Class eZ\\\\Publish\\\\SPI\\\\Persistence\\\\Content\\\\UrlAlias referenced with incorrect case\\: eZ\\\\Publish\\\\SPI\\\\Persistence\\\\Content\\\\URLAlias\\.$#"
515505
count: 2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<?php
2+
3+
/**
4+
* @copyright Copyright (C) Ibexa AS. All rights reserved.
5+
* @license For full copyright and license information view LICENSE file distributed with this source code.
6+
*/
7+
declare(strict_types=1);
8+
9+
namespace Ibexa\Tests\Core\Search\Common\EventSubscriber;
10+
11+
use eZ\Publish\API\Repository\Events\Trash\DeleteTrashItemEvent;
12+
use eZ\Publish\API\Repository\Values\Content\Trash\TrashItemDeleteResult;
13+
use eZ\Publish\Core\Repository\Values\Content\TrashItem;
14+
use eZ\Publish\Core\Search\Common\EventSubscriber\TrashEventSubscriber;
15+
use eZ\Publish\SPI\Persistence\Content as PersistenceContent;
16+
use eZ\Publish\SPI\Persistence\Content\Handler;
17+
use eZ\Publish\SPI\Persistence\Handler as PersistenceHandler;
18+
use eZ\Publish\SPI\Search\Handler as SearchHandler;
19+
use PHPUnit\Framework\TestCase;
20+
21+
final class TrashEventSubscriberTest extends TestCase
22+
{
23+
/** @var \eZ\Publish\SPI\Search\Handler&\PHPUnit\Framework\MockObject\MockObject */
24+
private $searchHandler;
25+
26+
/** @var \eZ\Publish\SPI\Persistence\Handler&\PHPUnit\Framework\MockObject\MockObject */
27+
private $persistenceHandler;
28+
29+
/** @var \eZ\Publish\Core\Search\Common\EventSubscriber\TrashEventSubscriber */
30+
private $subscriber;
31+
32+
protected function setUp(): void
33+
{
34+
$this->searchHandler = $this->createMock(SearchHandler::class);
35+
$this->persistenceHandler = $this->createMock(PersistenceHandler::class);
36+
37+
$this->subscriber = new TrashEventSubscriber(
38+
$this->searchHandler,
39+
$this->persistenceHandler
40+
);
41+
}
42+
43+
public function testOnDeleteTrashItem(): void
44+
{
45+
$trashItem = new TrashItem(['id' => 12345]);
46+
$reverseRelationContentId = 12;
47+
$trashItemDeleteResult = new TrashItemDeleteResult(
48+
[
49+
'trashItemId' => $trashItem->id,
50+
'reverseRelationContentIds' => [$reverseRelationContentId],
51+
]
52+
);
53+
54+
$this->persistenceHandler
55+
->expects(self::once())
56+
->method('contentHandler')
57+
->willReturn($contentHandler = $this->createMock(Handler::class));
58+
59+
$contentHandler
60+
->expects(self::once())
61+
->method('load')
62+
->with($reverseRelationContentId)
63+
->willReturn($content = new PersistenceContent());
64+
65+
$this->searchHandler
66+
->expects(self::once())
67+
->method('indexContent')
68+
->with($content);
69+
70+
$this->subscriber->onDeleteTrashItem(
71+
new DeleteTrashItemEvent(
72+
$trashItemDeleteResult,
73+
$trashItem,
74+
)
75+
);
76+
}
77+
}

0 commit comments

Comments
 (0)