Skip to content

Commit

Permalink
IBX-7346: Reindexed reverse-related content after deleting source con…
Browse files Browse the repository at this point in the history
…tent (#396)
  • Loading branch information
barw4 authored Dec 27, 2023
1 parent 4abba92 commit 29489e4
Show file tree
Hide file tree
Showing 6 changed files with 174 additions and 62 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,7 @@ class TrashItemDeleteResult extends ValueObject
* @var bool
*/
public $contentRemoved = false;

/** @var array<int> */
public $reverseRelationContentIds = [];
}
Original file line number Diff line number Diff line change
Expand Up @@ -246,11 +246,14 @@ protected function delete(Trashed $trashItem)
$result->trashItemId = $trashItem->id;
$result->contentId = $trashItem->contentId;

$reverseRelations = $this->contentHandler->loadReverseRelations($trashItem->contentId);

$this->locationGateway->removeElementFromTrash($trashItem->id);

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

return $result;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ public function testLoadTrashItem()
/**
* @covers \eZ\Publish\Core\Persistence\Legacy\Content\Location\Trash\Handler::emptyTrash
*/
public function testEmptyTrash()
public function testEmptyTrash(): void
{
$handler = $this->getTrashHandler();

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

$this->locationGateway
->expects($this->at($i++))
->expects(self::at($i++))
->method('countTrashed')
->willReturn(2);

$this->locationGateway
->expects($this->at($i++))
->expects(self::at($i++))
->method('listTrashed')
->will(
$this->returnValue($expectedTrashed)
);
->willReturn($expectedTrashed);

$trashedItemIds = [];
$trashedContentIds = [];

foreach ($expectedTrashed as $trashedElement) {
$this->locationMapper
->expects($this->at($iLocation++))
->expects(self::at($iLocation++))
->method('createLocationFromRow')
->will(
$this->returnValue(
new Trashed(
[
'id' => $trashedElement['node_id'],
'contentId' => $trashedElement['contentobject_id'],
'pathString' => $trashedElement['path_string'],
]
)
->willReturn(
new Trashed(
[
'id' => $trashedElement['node_id'],
'contentId' => $trashedElement['contentobject_id'],
'pathString' => $trashedElement['path_string'],
]
)
);

$this->contentHandler
->expects(self::at($iContent++))
->method('loadReverseRelations')
->with($trashedElement['contentobject_id'])
->willReturn([]);

$this->locationGateway
->expects($this->at($i++))
->expects(self::at($i++))
->method('removeElementFromTrash')
->with($trashedElement['node_id']);

$this->locationGateway
->expects($this->at($i++))
->expects(self::at($i++))
->method('countLocationsByContentId')
->with($trashedElement['contentobject_id'])
->will($this->returnValue(0));
->willReturn(0);

$this->contentHandler
->expects($this->at($iContent++))
->expects(self::at($iContent++))
->method('deleteContent')
->with($trashedElement['contentobject_id']);

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

$returnValue = $handler->emptyTrash();

$this->assertInstanceOf(TrashItemDeleteResultList::class, $returnValue);
self::assertInstanceOf(TrashItemDeleteResultList::class, $returnValue);

foreach ($returnValue->items as $key => $trashItemDeleteResult) {
$this->assertEquals($trashItemDeleteResult->trashItemId, $trashedItemIds[$key]);
$this->assertEquals($trashItemDeleteResult->contentId, $trashedContentIds[$key]);
$this->assertTrue($trashItemDeleteResult->contentRemoved);
self::assertEquals($trashItemDeleteResult->trashItemId, $trashedItemIds[$key]);
self::assertEquals($trashItemDeleteResult->contentId, $trashedContentIds[$key]);
self::assertTrue($trashItemDeleteResult->contentRemoved);
}
}

/**
* @covers \eZ\Publish\Core\Persistence\Legacy\Content\Location\Trash\Handler::deleteTrashItem
*/
public function testDeleteTrashItemNoMoreLocations()
public function testDeleteTrashItemNoMoreLocations(): void
{
$handler = $this->getTrashHandler();

$trashItemId = 69;
$contentId = 67;

$this->locationGateway
->expects($this->once())
->expects(self::once())
->method('loadTrashByLocation')
->with($trashItemId)
->will(
$this->returnValue(
[
'node_id' => $trashItemId,
'contentobject_id' => $contentId,
'path_string' => '/1/2/69',
]
)
->willReturn(
[
'node_id' => $trashItemId,
'contentobject_id' => $contentId,
'path_string' => '/1/2/69',
]
);

$this->locationMapper
->expects($this->once())
->expects(self::once())
->method('createLocationFromRow')
->will(
$this->returnValue(
new Trashed(
[
'id' => $trashItemId,
'contentId' => $contentId,
'pathString' => '/1/2/69',
]
)
->willReturn(
new Trashed(
[
'id' => $trashItemId,
'contentId' => $contentId,
'pathString' => '/1/2/69',
]
)
);

$this->contentHandler
->expects(self::once())
->method('loadReverseRelations')
->with($contentId)
->willReturn([]);

$this->locationGateway
->expects($this->once())
->expects(self::once())
->method('removeElementFromTrash')
->with($trashItemId);

$this->locationGateway
->expects($this->once())
->expects(self::once())
->method('countLocationsByContentId')
->with($contentId)
->will($this->returnValue(0));
->willReturn(0);

$this->contentHandler
->expects($this->once())
->expects(self::once())
->method('deleteContent')
->with($contentId);

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

$this->assertInstanceOf(TrashItemDeleteResult::class, $trashItemDeleteResult);
$this->assertEquals($trashItemId, $trashItemDeleteResult->trashItemId);
$this->assertEquals($contentId, $trashItemDeleteResult->contentId);
$this->assertTrue($trashItemDeleteResult->contentRemoved);
self::assertInstanceOf(TrashItemDeleteResult::class, $trashItemDeleteResult);
self::assertEquals($trashItemId, $trashItemDeleteResult->trashItemId);
self::assertEquals($contentId, $trashItemDeleteResult->contentId);
self::assertTrue($trashItemDeleteResult->contentRemoved);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
*/
namespace eZ\Publish\Core\Search\Common\EventSubscriber;

use eZ\Publish\API\Repository\Events\Trash\DeleteTrashItemEvent;
use eZ\Publish\API\Repository\Events\Trash\EmptyTrashEvent;
use eZ\Publish\API\Repository\Events\Trash\RecoverEvent;
use eZ\Publish\API\Repository\Events\Trash\TrashEvent;
use eZ\Publish\API\Repository\Values\Content\TrashItem;
Expand All @@ -18,6 +20,8 @@ public static function getSubscribedEvents(): array
return [
RecoverEvent::class => 'onRecover',
TrashEvent::class => 'onTrash',
DeleteTrashItemEvent::class => 'onDeleteTrashItem',
EmptyTrashEvent::class => 'onEmptyTrashEvent',
];
}

Expand All @@ -39,4 +43,33 @@ public function onTrash(TrashEvent $event)
$event->getLocation()->contentId
);
}

public function onDeleteTrashItem(DeleteTrashItemEvent $event): void
{
$contentHandler = $this->persistenceHandler->contentHandler();

$reverseRelationContentIds = $event->getResult()->reverseRelationContentIds;
foreach ($reverseRelationContentIds as $contentId) {
$persistenceContent = $contentHandler->load($contentId);

$this->searchHandler->indexContent($persistenceContent);
}
}

public function onEmptyTrashEvent(EmptyTrashEvent $event): void
{
$contentHandler = $this->persistenceHandler->contentHandler();

$results = $event->getResultList()->getIterator();

/** @var \eZ\Publish\API\Repository\Values\Content\Trash\TrashItemDeleteResult $result */
foreach ($results as $result) {
$reverseRelationContentIds = $result->reverseRelationContentIds;
foreach ($reverseRelationContentIds as $contentId) {
$persistenceContent = $contentHandler->load($contentId);

$this->searchHandler->indexContent($persistenceContent);
}
}
}
}
10 changes: 0 additions & 10 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -280,11 +280,6 @@ parameters:
count: 3
path: eZ/Publish/API/Repository/Tests/SearchServiceTranslationLanguageFallbackTest.php

-
message: "#^Undefined variable\\: \\$loader$#"
count: 3
path: eZ/Publish/API/Repository/Tests/SetupFactory/Legacy.php

-
message: "#^Method eZ\\\\Publish\\\\API\\\\Repository\\\\Tests\\\\URLWildcardServiceAuthorizationTest\\:\\:testCreateThrowsUnauthorizedException\\(\\) should return eZ\\\\Publish\\\\API\\\\Repository\\\\Values\\\\Content\\\\URLWildcard but return statement is missing\\.$#"
count: 1
Expand Down Expand Up @@ -505,11 +500,6 @@ parameters:
count: 1
path: eZ/Publish/Core/Persistence/Legacy/Content/Type/Handler.php

-
message: "#^Undefined variable\\: \\$loader$#"
count: 2
path: eZ/Publish/Core/Persistence/Legacy/Tests/HandlerTest.php

-
message: "#^Class eZ\\\\Publish\\\\SPI\\\\Persistence\\\\Content\\\\UrlAlias referenced with incorrect case\\: eZ\\\\Publish\\\\SPI\\\\Persistence\\\\Content\\\\URLAlias\\.$#"
count: 2
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?php

/**
* @copyright Copyright (C) Ibexa AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/
declare(strict_types=1);

namespace Ibexa\Tests\Core\Search\Common\EventSubscriber;

use eZ\Publish\API\Repository\Events\Trash\DeleteTrashItemEvent;
use eZ\Publish\API\Repository\Values\Content\Trash\TrashItemDeleteResult;
use eZ\Publish\Core\Repository\Values\Content\TrashItem;
use eZ\Publish\Core\Search\Common\EventSubscriber\TrashEventSubscriber;
use eZ\Publish\SPI\Persistence\Content as PersistenceContent;
use eZ\Publish\SPI\Persistence\Content\Handler;
use eZ\Publish\SPI\Persistence\Handler as PersistenceHandler;
use eZ\Publish\SPI\Search\Handler as SearchHandler;
use PHPUnit\Framework\TestCase;

final class TrashEventSubscriberTest extends TestCase
{
/** @var \eZ\Publish\SPI\Search\Handler&\PHPUnit\Framework\MockObject\MockObject */
private $searchHandler;

/** @var \eZ\Publish\SPI\Persistence\Handler&\PHPUnit\Framework\MockObject\MockObject */
private $persistenceHandler;

/** @var \eZ\Publish\Core\Search\Common\EventSubscriber\TrashEventSubscriber */
private $subscriber;

protected function setUp(): void
{
$this->searchHandler = $this->createMock(SearchHandler::class);
$this->persistenceHandler = $this->createMock(PersistenceHandler::class);

$this->subscriber = new TrashEventSubscriber(
$this->searchHandler,
$this->persistenceHandler
);
}

public function testOnDeleteTrashItem(): void
{
$trashItem = new TrashItem(['id' => 12345]);
$reverseRelationContentId = 12;
$trashItemDeleteResult = new TrashItemDeleteResult(
[
'trashItemId' => $trashItem->id,
'reverseRelationContentIds' => [$reverseRelationContentId],
]
);

$this->persistenceHandler
->expects(self::once())
->method('contentHandler')
->willReturn($contentHandler = $this->createMock(Handler::class));

$contentHandler
->expects(self::once())
->method('load')
->with($reverseRelationContentId)
->willReturn($content = new PersistenceContent());

$this->searchHandler
->expects(self::once())
->method('indexContent')
->with($content);

$this->subscriber->onDeleteTrashItem(
new DeleteTrashItemEvent(
$trashItemDeleteResult,
$trashItem,
)
);
}
}

0 comments on commit 29489e4

Please sign in to comment.