From d160d9019ac12eb7177cea9091329217994061e7 Mon Sep 17 00:00:00 2001 From: Nattfarinn Date: Mon, 26 Mar 2018 16:16:27 +0200 Subject: [PATCH] EZP-28680: Error 500 after restoring related item in another location (#2288) --- .../Cache/Tests/TrashHandlerTest.php | 110 +++++++++++++++++- .../Core/Persistence/Cache/TrashHandler.php | 35 +++++- 2 files changed, 141 insertions(+), 4 deletions(-) diff --git a/eZ/Publish/Core/Persistence/Cache/Tests/TrashHandlerTest.php b/eZ/Publish/Core/Persistence/Cache/Tests/TrashHandlerTest.php index 5c450fed92c..561b58982af 100644 --- a/eZ/Publish/Core/Persistence/Cache/Tests/TrashHandlerTest.php +++ b/eZ/Publish/Core/Persistence/Cache/Tests/TrashHandlerTest.php @@ -8,6 +8,9 @@ */ namespace eZ\Publish\Core\Persistence\Cache\Tests; +use eZ\Publish\Core\Persistence\Cache\ContentHandler; +use eZ\Publish\Core\Persistence\Cache\LocationHandler; +use eZ\Publish\SPI\Persistence\Content\Location; use eZ\Publish\SPI\Persistence\Content\Location\Trash\Handler as TrashHandler; /** @@ -30,8 +33,6 @@ public function providerForUnCachedMethods(): array // string $method, array $arguments, array? $tags, string? $key return [ ['loadTrashItem', [6]], - ['trashSubtree', [6], ['location-6', 'location-path-6']], - ['recover', [6, 2], ['location-6', 'location-path-6']], ['emptyTrash', []], ['deleteTrashItem', [6]], ]; @@ -43,4 +44,109 @@ public function providerForCachedLoadMethods(): array return [ ]; } + + public function testRecover() + { + $originalLocationId = 6; + $targetLocationId = 2; + $contentId = 42; + + $tags = [ + 'content-' . $contentId, + 'content-fields-' . $contentId, + 'location-' . $originalLocationId, + 'location-path-' . $originalLocationId, + ]; + + $handlerMethodName = $this->getHandlerMethodName(); + + $this->loggerMock->expects($this->once())->method('logCall'); + + $innerHandler = $this->createMock($this->getHandlerClassName()); + $contentHandlerMock = $this->createMock(ContentHandler::class); + $locationHandlerMock = $this->createMock(LocationHandler::class); + + $locationHandlerMock + ->method('load') + ->will($this->returnValue(new Location(['id' => $originalLocationId, 'contentId' => $contentId]))); + + $this->persistenceHandlerMock + ->method('contentHandler') + ->will($this->returnValue($contentHandlerMock)); + + $this->persistenceHandlerMock + ->method('locationHandler') + ->will($this->returnValue($locationHandlerMock)); + + $this->persistenceHandlerMock + ->expects($this->once()) + ->method($handlerMethodName) + ->will($this->returnValue($innerHandler)); + + $innerHandler + ->expects($this->once()) + ->method('recover') + ->with($originalLocationId, $targetLocationId) + ->will($this->returnValue(null)); + + $this->cacheMock + ->expects($this->once()) + ->method('invalidateTags') + ->with($tags); + + $handler = $this->persistenceCacheHandler->$handlerMethodName(); + $handler->recover($originalLocationId, $targetLocationId); + } + + public function testTrashSubtree() + { + $locationId = 6; + $contentId = 42; + + $tags = [ + 'content-' . $contentId, + 'content-fields-' . $contentId, + 'location-' . $locationId, + 'location-path-' . $locationId, + ]; + + $handlerMethodName = $this->getHandlerMethodName(); + + $this->loggerMock->expects($this->once())->method('logCall'); + + $innerHandler = $this->createMock($this->getHandlerClassName()); + $contentHandlerMock = $this->createMock(ContentHandler::class); + $locationHandlerMock = $this->createMock(LocationHandler::class); + + $locationHandlerMock + ->method('load') + ->will($this->returnValue(new Location(['id' => $locationId, 'contentId' => $contentId]))); + + $this->persistenceHandlerMock + ->method('contentHandler') + ->will($this->returnValue($contentHandlerMock)); + + $this->persistenceHandlerMock + ->method('locationHandler') + ->will($this->returnValue($locationHandlerMock)); + + $this->persistenceHandlerMock + ->expects($this->once()) + ->method($handlerMethodName) + ->will($this->returnValue($innerHandler)); + + $innerHandler + ->expects($this->once()) + ->method('trashSubtree') + ->with($locationId) + ->will($this->returnValue(null)); + + $this->cacheMock + ->expects($this->once()) + ->method('invalidateTags') + ->with($tags); + + $handler = $this->persistenceCacheHandler->$handlerMethodName(); + $handler->trashSubtree($locationId); + } } diff --git a/eZ/Publish/Core/Persistence/Cache/TrashHandler.php b/eZ/Publish/Core/Persistence/Cache/TrashHandler.php index 66fab37477d..219b5d07db6 100644 --- a/eZ/Publish/Core/Persistence/Cache/TrashHandler.php +++ b/eZ/Publish/Core/Persistence/Cache/TrashHandler.php @@ -10,6 +10,7 @@ use eZ\Publish\SPI\Persistence\Content\Location\Trash\Handler as TrashHandlerInterface; use eZ\Publish\API\Repository\Values\Content\Query\Criterion; +use eZ\Publish\SPI\Persistence\Content\Relation; /** * @see \eZ\Publish\SPI\Persistence\Content\Location\Trash\Handler @@ -32,9 +33,24 @@ public function loadTrashItem($id) public function trashSubtree($locationId) { $this->logger->logCall(__METHOD__, array('locationId' => $locationId)); + + $location = $this->persistenceHandler->locationHandler()->load($locationId); + $reverseRelations = $this->persistenceHandler->contentHandler()->loadRelations($location->contentId); + $return = $this->persistenceHandler->trashHandler()->trashSubtree($locationId); - $this->cache->invalidateTags(['location-' . $locationId, 'location-path-' . $locationId]); + $tags = []; + if (!empty($reverseRelations)) { + $tags = array_map(function (Relation $relation) { + return 'content-fields-' . $relation->destinationContentId; + }, $reverseRelations); + } + + $this->cache->invalidateTags([ + 'content-' . $location->contentId, + 'content-fields-' . $location->contentId, + 'location-' . $locationId, 'location-path-' . $locationId, + ] + $tags); return $return; } @@ -45,9 +61,24 @@ public function trashSubtree($locationId) public function recover($trashedId, $newParentId) { $this->logger->logCall(__METHOD__, array('id' => $trashedId, 'newParentId' => $newParentId)); + $return = $this->persistenceHandler->trashHandler()->recover($trashedId, $newParentId); - $this->cache->invalidateTags(['location-' . $trashedId, 'location-path-' . $trashedId]); + $location = $this->persistenceHandler->locationHandler()->load($return); + $reverseRelations = $this->persistenceHandler->contentHandler()->loadRelations($location->contentId); + + $tags = []; + if (!empty($reverseRelations)) { + $tags = array_map(function (Relation $relation) { + return 'content-fields-' . $relation->destinationContentId; + }, $reverseRelations); + } + + $this->cache->invalidateTags([ + 'content-' . $location->contentId, + 'content-fields-' . $location->contentId, + 'location-' . $trashedId, 'location-path-' . $trashedId, + ] + $tags); return $return; }