diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index f16c7e02..1de0fbed 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1230,11 +1230,26 @@ parameters: count: 1 path: tests/lib/Event/Subscriber/AbstractCoreEventSubscriberTest.php + - + message: "#^PHPDoc tag @var for property EzSystems\\\\EzRecommendationClient\\\\Tests\\\\Event\\\\Subscriber\\\\AbstractCoreEventSubscriberTest\\:\\:\\$notificationServiceMock contains unresolvable type\\.$#" + count: 1 + path: tests/lib/Event/Subscriber/AbstractCoreEventSubscriberTest.php + - message: "#^Return type of call to method PHPUnit\\\\Framework\\\\TestCase\\:\\:createMock\\(\\) contains unresolvable type\\.$#" count: 1 path: tests/lib/Event/Subscriber/AbstractCoreEventSubscriberTest.php + - + message: "#^PHPDoc tag @var for property EzSystems\\\\EzRecommendationClient\\\\Tests\\\\Event\\\\Subscriber\\\\AbstractRepositoryEventSubscriberTest\\:\\:\\$contentHelperMock contains unresolvable type\\.$#" + count: 1 + path: tests/lib/Event/Subscriber/AbstractRepositoryEventSubscriberTest.php + + - + message: "#^PHPDoc tag @var for property EzSystems\\\\EzRecommendationClient\\\\Tests\\\\Event\\\\Subscriber\\\\AbstractRepositoryEventSubscriberTest\\:\\:\\$locationHelperMock contains unresolvable type\\.$#" + count: 1 + path: tests/lib/Event/Subscriber/AbstractRepositoryEventSubscriberTest.php + - message: "#^Return type of call to method PHPUnit\\\\Framework\\\\TestCase\\:\\:createMock\\(\\) contains unresolvable type\\.$#" count: 2 @@ -1315,21 +1330,11 @@ parameters: count: 1 path: tests/lib/Event/Subscriber/ContentEventSubscriberTest.php - - - message: "#^Parameter \\#1 \\$notificationService of class EzSystems\\\\EzRecommendationClient\\\\Event\\\\Subscriber\\\\ContentEventSubscriber constructor expects EzSystems\\\\EzRecommendationClient\\\\Service\\\\NotificationService, EzSystems\\\\EzRecommendationClient\\\\Service\\\\EventNotificationService\\|PHPUnit\\\\Framework\\\\MockObject\\\\MockObject given\\.$#" - count: 1 - path: tests/lib/Event/Subscriber/ContentEventSubscriberTest.php - - message: "#^Return type of call to method PHPUnit\\\\Framework\\\\TestCase\\:\\:createMock\\(\\) contains unresolvable type\\.$#" count: 6 path: tests/lib/Event/Subscriber/ContentEventSubscriberTest.php - - - message: "#^Call to an undefined method EzSystems\\\\EzRecommendationClient\\\\Helper\\\\ContentHelper\\|PHPUnit\\\\Framework\\\\MockObject\\\\MockObject\\:\\:expects\\(\\)\\.$#" - count: 4 - path: tests/lib/Event/Subscriber/LocationEventSubscriberTest.php - - message: "#^Method EzSystems\\\\EzRecommendationClient\\\\Tests\\\\Event\\\\Subscriber\\\\LocationEventSubscriberTest\\:\\:subscribedEventsDataProvider\\(\\) return type has no value type specified in iterable type array\\.$#" count: 1 @@ -1380,31 +1385,11 @@ parameters: count: 1 path: tests/lib/Event/Subscriber/LocationEventSubscriberTest.php - - - message: "#^Method EzSystems\\\\EzRecommendationClient\\\\Tests\\\\Event\\\\Subscriber\\\\LocationEventSubscriberTest\\:\\:updateLocationWithChildrenDataProvider\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/lib/Event/Subscriber/LocationEventSubscriberTest.php - - - - message: "#^Parameter \\#1 \\$notificationService of class EzSystems\\\\EzRecommendationClient\\\\Event\\\\Subscriber\\\\LocationEventSubscriber constructor expects EzSystems\\\\EzRecommendationClient\\\\Service\\\\NotificationService, EzSystems\\\\EzRecommendationClient\\\\Service\\\\EventNotificationService\\|PHPUnit\\\\Framework\\\\MockObject\\\\MockObject given\\.$#" - count: 1 - path: tests/lib/Event/Subscriber/LocationEventSubscriberTest.php - - message: "#^Parameter \\#1 \\$originalClassName of method PHPUnit\\\\Framework\\\\TestCase\\:\\:createMock\\(\\) expects class\\-string\\, string given\\.$#" count: 1 path: tests/lib/Event/Subscriber/LocationEventSubscriberTest.php - - - message: "#^Parameter \\#4 \\$locationHelper of class EzSystems\\\\EzRecommendationClient\\\\Event\\\\Subscriber\\\\LocationEventSubscriber constructor expects EzSystems\\\\EzRecommendationClient\\\\Helper\\\\LocationHelper, EzSystems\\\\EzRecommendationClient\\\\Helper\\\\LocationHelper\\|PHPUnit\\\\Framework\\\\MockObject\\\\MockObject given\\.$#" - count: 1 - path: tests/lib/Event/Subscriber/LocationEventSubscriberTest.php - - - - message: "#^Parameter \\#5 \\$contentHelper of class EzSystems\\\\EzRecommendationClient\\\\Event\\\\Subscriber\\\\LocationEventSubscriber constructor expects EzSystems\\\\EzRecommendationClient\\\\Helper\\\\ContentHelper, EzSystems\\\\EzRecommendationClient\\\\Helper\\\\ContentHelper\\|PHPUnit\\\\Framework\\\\MockObject\\\\MockObject given\\.$#" - count: 1 - path: tests/lib/Event/Subscriber/LocationEventSubscriberTest.php - - message: "#^Return type of call to method PHPUnit\\\\Framework\\\\TestCase\\:\\:createMock\\(\\) contains unresolvable type\\.$#" count: 7 @@ -1430,21 +1415,11 @@ parameters: count: 1 path: tests/lib/Event/Subscriber/ObjectStateEventSubscriberTest.php - - - message: "#^Parameter \\#1 \\$notificationService of class EzSystems\\\\EzRecommendationClient\\\\Event\\\\Subscriber\\\\ObjectStateEventSubscriber constructor expects EzSystems\\\\EzRecommendationClient\\\\Service\\\\NotificationService, EzSystems\\\\EzRecommendationClient\\\\Service\\\\EventNotificationService\\|PHPUnit\\\\Framework\\\\MockObject\\\\MockObject given\\.$#" - count: 1 - path: tests/lib/Event/Subscriber/ObjectStateEventSubscriberTest.php - - message: "#^Return type of call to method PHPUnit\\\\Framework\\\\TestCase\\:\\:createMock\\(\\) contains unresolvable type\\.$#" count: 1 path: tests/lib/Event/Subscriber/ObjectStateEventSubscriberTest.php - - - message: "#^Anonymous function has an unused use \\$contentInfo\\.$#" - count: 2 - path: tests/lib/Event/Subscriber/TrashEventSubscriberTest.php - - message: "#^Method EzSystems\\\\EzRecommendationClient\\\\Tests\\\\Event\\\\Subscriber\\\\TrashEventSubscriberTest\\:\\:getRelationList\\(\\) has no return type specified\\.$#" count: 1 @@ -1475,21 +1450,6 @@ parameters: count: 1 path: tests/lib/Event/Subscriber/TrashEventSubscriberTest.php - - - message: "#^Parameter \\#1 \\$notificationService of class EzSystems\\\\EzRecommendationClient\\\\Event\\\\Subscriber\\\\TrashEventSubscriber constructor expects EzSystems\\\\EzRecommendationClient\\\\Service\\\\NotificationService, EzSystems\\\\EzRecommendationClient\\\\Service\\\\EventNotificationService\\|PHPUnit\\\\Framework\\\\MockObject\\\\MockObject given\\.$#" - count: 1 - path: tests/lib/Event/Subscriber/TrashEventSubscriberTest.php - - - - message: "#^Parameter \\#4 \\$locationHelper of class EzSystems\\\\EzRecommendationClient\\\\Event\\\\Subscriber\\\\TrashEventSubscriber constructor expects EzSystems\\\\EzRecommendationClient\\\\Helper\\\\LocationHelper, EzSystems\\\\EzRecommendationClient\\\\Helper\\\\LocationHelper\\|PHPUnit\\\\Framework\\\\MockObject\\\\MockObject given\\.$#" - count: 1 - path: tests/lib/Event/Subscriber/TrashEventSubscriberTest.php - - - - message: "#^Parameter \\#5 \\$contentHelper of class EzSystems\\\\EzRecommendationClient\\\\Event\\\\Subscriber\\\\TrashEventSubscriber constructor expects EzSystems\\\\EzRecommendationClient\\\\Helper\\\\ContentHelper, EzSystems\\\\EzRecommendationClient\\\\Helper\\\\ContentHelper\\|PHPUnit\\\\Framework\\\\MockObject\\\\MockObject given\\.$#" - count: 1 - path: tests/lib/Event/Subscriber/TrashEventSubscriberTest.php - - message: "#^Return type of call to method PHPUnit\\\\Framework\\\\TestCase\\:\\:createMock\\(\\) contains unresolvable type\\.$#" count: 2 diff --git a/src/lib/Event/Subscriber/AbstractRepositoryEventSubscriber.php b/src/lib/Event/Subscriber/AbstractRepositoryEventSubscriber.php index eab48c9d..23b6163e 100644 --- a/src/lib/Event/Subscriber/AbstractRepositoryEventSubscriber.php +++ b/src/lib/Event/Subscriber/AbstractRepositoryEventSubscriber.php @@ -10,7 +10,9 @@ use eZ\Publish\API\Repository\ContentService as ContentServiceInterface; use eZ\Publish\API\Repository\LocationService as LocationServiceInterface; +use eZ\Publish\API\Repository\SearchService; use eZ\Publish\API\Repository\Values\Content\Location; +use eZ\Publish\Core\Query\QueryFactoryInterface; use EzSystems\EzRecommendationClient\Helper\ContentHelper; use EzSystems\EzRecommendationClient\Helper\LocationHelper; use EzSystems\EzRecommendationClient\Service\NotificationService; @@ -29,33 +31,64 @@ abstract class AbstractRepositoryEventSubscriber extends AbstractCoreEventSubscr /** @var \EzSystems\EzRecommendationClient\Helper\ContentHelper */ protected $contentHelper; + /** @var \eZ\Publish\Core\Query\QueryFactoryInterface */ + private $queryFactory; + + /** @var \eZ\Publish\API\Repository\SearchService */ + private $searchService; + public function __construct( NotificationService $notificationService, ContentServiceInterface $contentService, LocationServiceInterface $locationService, LocationHelper $locationHelper, - ContentHelper $contentHelper + ContentHelper $contentHelper, + QueryFactoryInterface $queryFactory, + SearchService $searchService ) { parent::__construct($notificationService); $this->contentService = $contentService; $this->locationService = $locationService; $this->locationHelper = $locationHelper; $this->contentHelper = $contentHelper; + $this->queryFactory = $queryFactory; + $this->searchService = $searchService; } /** + * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException */ protected function updateLocationSubtree(Location $location, string $method, string $action): void { - $subtree = $this->locationService->loadLocationChildren($location); + $locationChildren = $this->loadLocationChildren($location); - /** @var \eZ\Publish\API\Repository\Values\Content\Location $content */ - foreach ($subtree as $content) { + foreach ($locationChildren as $locationChild) { $this->notificationService->sendNotification( - $method, $action, $content->getContentInfo() + $method, $action, $locationChild->getContentInfo() ); } } + + /** + * @return array<\eZ\Publish\API\Repository\Values\Content\Location> + * + * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException + */ + protected function loadLocationChildren(Location $location): array + { + /** @var \eZ\Publish\API\Repository\Values\Content\LocationQuery $locationChildrenQuery */ + $locationChildrenQuery = $this->queryFactory->create('Children', ['location' => $location]); + $searchResult = $this->searchService->findLocations($locationChildrenQuery); + + $locations = []; + foreach ($searchResult->searchHits as $searchHit) { + /** @var \eZ\Publish\API\Repository\Values\Content\Location $locationChild */ + $locationChild = $searchHit->valueObject; + $locations[] = $locationChild; + } + + return $locations; + } } diff --git a/src/lib/Event/Subscriber/LocationEventSubscriber.php b/src/lib/Event/Subscriber/LocationEventSubscriber.php index 30fb4135..859c316b 100644 --- a/src/lib/Event/Subscriber/LocationEventSubscriber.php +++ b/src/lib/Event/Subscriber/LocationEventSubscriber.php @@ -128,15 +128,13 @@ public function onUpdateLocation(UpdateLocationEvent $event): void /** * @throws \eZ\Publish\API\Repository\Exceptions\BadStateException + * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException */ private function hideLocation(Location $location, bool $isChild = false): void { - $children = $this->locationService->loadLocationChildren($location)->locations; - - /** @var \eZ\Publish\API\Repository\Values\Content\Location $child */ - foreach ($children as $child) { + foreach ($this->loadLocationChildren($location) as $child) { $this->hideLocation($child, true); } @@ -158,15 +156,13 @@ private function hideLocation(Location $location, bool $isChild = false): void } /** + * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException */ private function updateLocationWithChildren(Location $location, string $method, string $action): void { - $children = $this->locationService->loadLocationChildren($location)->locations; - - /** @var \eZ\Publish\API\Repository\Values\Content\Location $child */ - foreach ($children as $child) { + foreach ($this->loadLocationChildren($location) as $child) { $this->updateLocationWithChildren($child, $method, $action); } diff --git a/src/lib/Event/Subscriber/TrashEventSubscriber.php b/src/lib/Event/Subscriber/TrashEventSubscriber.php index a5ef59e4..e82e9e0c 100644 --- a/src/lib/Event/Subscriber/TrashEventSubscriber.php +++ b/src/lib/Event/Subscriber/TrashEventSubscriber.php @@ -13,7 +13,9 @@ use eZ\Publish\API\Repository\Events\Trash\TrashEvent; use eZ\Publish\API\Repository\LocationService as LocationServiceInterface; use eZ\Publish\API\Repository\Repository; +use eZ\Publish\API\Repository\SearchService; use eZ\Publish\API\Repository\Values\Content\ContentInfo; +use eZ\Publish\Core\Query\QueryFactoryInterface; use EzSystems\EzRecommendationClient\Helper\ContentHelper; use EzSystems\EzRecommendationClient\Helper\LocationHelper; use EzSystems\EzRecommendationClient\Service\NotificationService; @@ -31,9 +33,19 @@ public function __construct( LocationServiceInterface $locationService, LocationHelper $locationHelper, ContentHelper $contentHelper, + QueryFactoryInterface $queryFactory, + SearchService $searchService, Repository $repository ) { - parent::__construct($notificationService, $contentService, $locationService, $locationHelper, $contentHelper); + parent::__construct( + $notificationService, + $contentService, + $locationService, + $locationHelper, + $contentHelper, + $queryFactory, + $searchService + ); $this->repository = $repository; } diff --git a/tests/lib/Event/Subscriber/AbstractCoreEventSubscriberTest.php b/tests/lib/Event/Subscriber/AbstractCoreEventSubscriberTest.php index 7304500e..4decc705 100644 --- a/tests/lib/Event/Subscriber/AbstractCoreEventSubscriberTest.php +++ b/tests/lib/Event/Subscriber/AbstractCoreEventSubscriberTest.php @@ -18,9 +18,6 @@ abstract class AbstractCoreEventSubscriberTest extends TestCase { - /** @var \PHPUnit\Framework\MockObject\MockObject|\EzSystems\EzRecommendationClient\Service\EventNotificationService */ - protected $notificationServiceMock; - /** @var \eZ\Publish\API\Repository\Values\Content\ContentInfo */ protected $contentInfo; @@ -30,9 +27,11 @@ abstract class AbstractCoreEventSubscriberTest extends TestCase /** @var \eZ\Publish\Core\Repository\Values\Content\Content */ protected $content; + /** @var \PHPUnit\Framework\MockObject\MockObject&\EzSystems\EzRecommendationClient\Service\EventNotificationService */ + protected $notificationServiceMock; + public function setUp(): void { - $this->notificationServiceMock = $this->createMock(EventNotificationService::class); $this->contentInfo = new ContentInfo([ 'id' => 1, 'contentTypeId' => 2, @@ -47,6 +46,7 @@ public function setUp(): void 'contentInfo' => $this->contentInfo, ]), ]); + $this->notificationServiceMock = $this->createMock(EventNotificationService::class); } /** diff --git a/tests/lib/Event/Subscriber/AbstractRepositoryEventSubscriberTest.php b/tests/lib/Event/Subscriber/AbstractRepositoryEventSubscriberTest.php index e734d1e6..c96265bc 100644 --- a/tests/lib/Event/Subscriber/AbstractRepositoryEventSubscriberTest.php +++ b/tests/lib/Event/Subscriber/AbstractRepositoryEventSubscriberTest.php @@ -10,6 +10,8 @@ use eZ\Publish\API\Repository\ContentService; use eZ\Publish\API\Repository\LocationService; +use eZ\Publish\API\Repository\SearchService; +use eZ\Publish\Core\Query\QueryFactoryInterface; use EzSystems\EzRecommendationClient\Helper\ContentHelper; use EzSystems\EzRecommendationClient\Helper\LocationHelper; @@ -21,12 +23,18 @@ abstract class AbstractRepositoryEventSubscriberTest extends AbstractCoreEventSu /** @var \PHPUnit\Framework\MockObject\MockObject|\eZ\Publish\API\Repository\LocationService */ protected $locationServiceMock; - /** @var \PHPUnit\Framework\MockObject\MockObject|\EzSystems\EzRecommendationClient\Helper\LocationHelper */ + /** @var \PHPUnit\Framework\MockObject\MockObject&\EzSystems\EzRecommendationClient\Helper\LocationHelper */ protected $locationHelperMock; - /** @var \PHPUnit\Framework\MockObject\MockObject|\EzSystems\EzRecommendationClient\Helper\ContentHelper */ + /** @var \PHPUnit\Framework\MockObject\MockObject&\EzSystems\EzRecommendationClient\Helper\ContentHelper */ protected $contentHelperMock; + /** @var \PHPUnit\Framework\MockObject\MockObject&\eZ\Publish\Core\Query\QueryFactoryInterface */ + protected $queryFactoryMock; + + /** @var \PHPUnit\Framework\MockObject\MockObject&\eZ\Publish\API\Repository\SearchService */ + protected $searchServiceMock; + public function setUp(): void { parent::setUp(); @@ -35,5 +43,7 @@ public function setUp(): void $this->locationServiceMock = $this->createMock(LocationService::class); $this->locationHelperMock = $this->createMock(LocationHelper::class); $this->contentHelperMock = $this->createMock(ContentHelper::class); + $this->queryFactoryMock = $this->createMock(QueryFactoryInterface::class); + $this->searchServiceMock = $this->createMock(SearchService::class); } } diff --git a/tests/lib/Event/Subscriber/LocationEventSubscriberTest.php b/tests/lib/Event/Subscriber/LocationEventSubscriberTest.php index 5d74b9d8..f4546c98 100644 --- a/tests/lib/Event/Subscriber/LocationEventSubscriberTest.php +++ b/tests/lib/Event/Subscriber/LocationEventSubscriberTest.php @@ -16,7 +16,9 @@ use eZ\Publish\API\Repository\Events\Location\UnhideLocationEvent; use eZ\Publish\API\Repository\Events\Location\UpdateLocationEvent; use eZ\Publish\API\Repository\Values\Content\ContentInfo; -use eZ\Publish\API\Repository\Values\Content\LocationList; +use eZ\Publish\API\Repository\Values\Content\LocationQuery; +use eZ\Publish\API\Repository\Values\Content\Search\SearchHit; +use eZ\Publish\API\Repository\Values\Content\Search\SearchResult; use eZ\Publish\Core\Repository\Values\Content\Content; use eZ\Publish\Core\Repository\Values\Content\Location; use eZ\Publish\Core\Repository\Values\Content\VersionInfo; @@ -38,12 +40,6 @@ class LocationEventSubscriberTest extends AbstractRepositoryEventSubscriberTest /** @var \eZ\Publish\Core\Repository\Values\Content\Location */ private $location2; - /** @var \eZ\Publish\API\Repository\Values\Content\LocationList */ - private $emptyLocationChildren; - - /** @var \eZ\Publish\API\Repository\Values\Content\LocationList */ - private $locationChildren; - public function setUp(): void { parent::setUp(); @@ -53,7 +49,9 @@ public function setUp(): void $this->contentServiceMock, $this->locationServiceMock, $this->locationHelperMock, - $this->contentHelperMock + $this->contentHelperMock, + $this->queryFactoryMock, + $this->searchServiceMock ); $this->location1 = new Location([ 'id' => 20, @@ -65,17 +63,6 @@ public function setUp(): void 'path' => ['1', '5', '30'], 'contentInfo' => new ContentInfo(['id' => self::CONTENT_ID + 2]), ]); - $this->emptyLocationChildren = new LocationList([ - 'totalCount' => 0, - 'locations' => [], - ]); - $this->locationChildren = new LocationList([ - 'totalCount' => 2, - 'locations' => [ - $this->location1, - $this->location2, - ], - ]); } public function testCreateInstanceOfLocationEventSubscriber() @@ -105,15 +92,38 @@ public function testCallOnCopySubtreeMethod() { $event = $this->createMock(CopySubtreeEvent::class); $event - ->expects($this->once()) + ->expects(self::once()) ->method('getLocation') ->willReturn($this->location); - $this->locationServiceMock - ->expects($this->atLeastOnce()) - ->method('loadLocationChildren') - ->with($this->equalTo($this->location)) - ->willReturn($this->locationChildren); + $this->queryFactoryMock + ->method('create') + ->willReturn(new LocationQuery()); + + $this->searchServiceMock + ->method('findLocations') + ->willReturn(new SearchResult([ + 'searchHits' => [ + new SearchHit(['valueObject' => $this->location1]), + new SearchHit(['valueObject' => $this->location2]), + ], + ])); + + $this->notificationServiceMock + ->expects(self::exactly(2)) + ->method('sendNotification') + ->withConsecutive( + [ + 'EzSystems\EzRecommendationClient\Event\Subscriber\LocationEventSubscriber::onCopySubtree', + 'UPDATE', + $this->location1->getContentInfo(), + ], + [ + 'EzSystems\EzRecommendationClient\Event\Subscriber\LocationEventSubscriber::onCopySubtree', + 'UPDATE', + $this->location2->getContentInfo(), + ], + ); $this->locationEventSubscriber->onCopySubtree($event); } @@ -122,10 +132,19 @@ public function testCallOnCreateLocationMethod() { $event = $this->createMock(CreateLocationEvent::class); $event - ->expects($this->once()) + ->expects(self::once()) ->method('getContentInfo') ->willReturn($this->contentInfo); + $this->notificationServiceMock + ->expects(self::once()) + ->method('sendNotification') + ->with( + 'EzSystems\EzRecommendationClient\Event\Subscriber\LocationEventSubscriber::onCreateLocation', + 'UPDATE', + $this->contentInfo + ); + $this->locationEventSubscriber->onCreateLocation($event); } @@ -133,26 +152,36 @@ public function testCallOnHideLocationMethod() { $event = $this->createMock(HideLocationEvent::class); $event - ->expects($this->once()) ->method('getLocation') ->willReturn($this->location); $this->locationServiceMock - ->expects($this->atLeastOnce()) - ->method('loadLocationChildren') - ->with($this->equalTo($this->location)) - ->willReturn($this->emptyLocationChildren); - - $this->locationServiceMock - ->expects($this->atLeastOnce()) ->method('loadLocation') - ->willReturn($this->location); + ->wilLReturn($this->location); $this->contentHelperMock - ->expects($this->atLeastOnce()) ->method('getIncludedContent') ->willReturn($this->content); + $this->queryFactoryMock + ->method('create') + ->willReturn(new LocationQuery()); + + $this->searchServiceMock + ->method('findLocations') + ->willReturn(new SearchResult([])); + + $this->notificationServiceMock + ->expects(self::once()) + ->method('sendNotification') + ->withConsecutive( + [ + 'EzSystems\EzRecommendationClient\Event\Subscriber\LocationEventSubscriber::hideLocation', + 'DELETE', + $this->location->getContentInfo(), + ], + ); + $this->locationEventSubscriber->onHideLocation($event); } @@ -160,59 +189,107 @@ public function testCallOnMoveSubtreeMethod() { $event = $this->createMock(MoveSubtreeEvent::class); $event - ->expects($this->once()) + ->expects(self::once()) ->method('getLocation') ->willReturn($this->location); - $this->locationServiceMock - ->expects($this->atLeastOnce()) - ->method('loadLocationChildren') - ->with($this->equalTo($this->location)) - ->willReturn($this->locationChildren); + $this->queryFactoryMock + ->method('create') + ->willReturn(new LocationQuery()); + + $this->searchServiceMock + ->method('findLocations') + ->willReturn(new SearchResult([ + 'searchHits' => [ + new SearchHit(['valueObject' => $this->location1]), + new SearchHit(['valueObject' => $this->location2]), + ], + ])); + + $this->notificationServiceMock + ->expects(self::exactly(2)) + ->method('sendNotification') + ->withConsecutive( + [ + 'EzSystems\EzRecommendationClient\Event\Subscriber\LocationEventSubscriber::onMoveSubtree', + 'UPDATE', + $this->location1->getContentInfo(), + ], + [ + 'EzSystems\EzRecommendationClient\Event\Subscriber\LocationEventSubscriber::onMoveSubtree', + 'UPDATE', + $this->location2->getContentInfo(), + ], + ); $this->locationEventSubscriber->onMoveSubtree($event); } public function testCallOnSwapLocationMethod() { + $swappedLocationContentInfo = new ContentInfo(['id' => self::CONTENT_ID + 120]); $swappedLocation = new Location([ 'id' => 120, 'path' => ['1', '5', '120'], - 'contentInfo' => new ContentInfo(['id' => self::CONTENT_ID + 120]), + 'contentInfo' => $swappedLocationContentInfo, + ]); + $swappedLocationContent = new Content([ + 'versionInfo' => new VersionInfo([ + 'contentInfo' => new ContentInfo([ + 'id' => self::CONTENT_ID + 120, + ]), + ]), + 'internalFields' => [], ]); $event = $this->createMock(SwapLocationEvent::class); $event - ->expects($this->once()) + ->expects(self::once()) ->method('getLocation1') ->willReturn($this->location); $event - ->expects($this->once()) + ->expects(self::once()) ->method('getLocation2') ->willReturn($swappedLocation); - $this->locationServiceMock - ->expects($this->at(0)) - ->method('loadLocationChildren') - ->with($this->equalTo($this->location)) - ->willReturn($this->emptyLocationChildren); + $this->queryFactoryMock + ->method('create') + ->willReturn(new LocationQuery()); + + $this->searchServiceMock + ->method('findLocations') + ->willReturn(new SearchResult([])); $this->locationServiceMock - ->expects($this->at(1)) + ->expects(self::at(0)) ->method('loadLocation') ->willReturn($this->location); $this->locationServiceMock - ->expects($this->at(2)) - ->method('loadLocationChildren') - ->with($this->equalTo($swappedLocation)) - ->willReturn($this->emptyLocationChildren); - - $this->locationServiceMock - ->expects($this->at(3)) + ->expects(self::at(1)) ->method('loadLocation') ->willReturn($swappedLocation); + $this->contentHelperMock + ->method('getIncludedContent') + ->willReturnOnConsecutiveCalls($this->content, $swappedLocationContent); + + $this->notificationServiceMock + ->expects(self::exactly(2)) + ->method('sendNotification') + ->withConsecutive( + [ + 'EzSystems\EzRecommendationClient\Event\Subscriber\LocationEventSubscriber::swapLocation', + 'UPDATE', + $this->location->getContentInfo(), + ], + [ + 'EzSystems\EzRecommendationClient\Event\Subscriber\LocationEventSubscriber::swapLocation', + 'UPDATE', + $swappedLocationContentInfo, + ], + ); + $this->locationEventSubscriber->onSwapLocation($event); } @@ -220,21 +297,38 @@ public function testCallOnUnhideLocationMethod() { $event = $this->createMock(UnhideLocationEvent::class); $event - ->expects($this->once()) + ->expects(self::once()) ->method('getLocation') ->willReturn($this->location); - $this->locationServiceMock - ->expects($this->atLeastOnce()) - ->method('loadLocationChildren') - ->with($this->equalTo($this->location)) - ->willReturn($this->emptyLocationChildren); + $this->queryFactoryMock + ->method('create') + ->willReturn(new LocationQuery()); + + $this->searchServiceMock + ->method('findLocations') + ->willReturn(new SearchResult([])); $this->locationServiceMock - ->expects($this->atLeastOnce()) + ->expects(self::atLeastOnce()) ->method('loadLocation') ->willReturn($this->location); + $this->contentHelperMock + ->method('getIncludedContent') + ->willReturn($this->content); + + $this->notificationServiceMock + ->expects(self::once()) + ->method('sendNotification') + ->withConsecutive( + [ + 'EzSystems\EzRecommendationClient\Event\Subscriber\LocationEventSubscriber::onUnhideLocation', + 'UPDATE', + $this->location->getContentInfo(), + ], + ); + $this->locationEventSubscriber->onUnhideLocation($event); } @@ -242,102 +336,157 @@ public function testCallOnUpdateLocationMethod() { $event = $this->createMock(UpdateLocationEvent::class); $event - ->expects($this->once()) + ->expects(self::once()) ->method('getLocation') ->willReturn($this->location); + $this->notificationServiceMock + ->expects(self::once()) + ->method('sendNotification') + ->withConsecutive( + [ + 'EzSystems\EzRecommendationClient\Event\Subscriber\LocationEventSubscriber::onUpdateLocation', + 'UPDATE', + $this->location->getContentInfo(), + ], + ); + $this->locationEventSubscriber->onUpdateLocation($event); } /** * @dataProvider updateLocationWithChildrenDataProvider */ - public function testUpdateSingleLocationWithChildren(string $event, string $method) - { + public function testUpdateSingleLocationWithChildren( + string $event, + string $method, + string $expectedNotificationMethod, + string $expectedNotificationType + ) { $eventMock = $this->createMock($event); $eventMock - ->expects($this->once()) + ->expects(self::once()) ->method('getLocation') ->willReturn($this->location); - $this->locationServiceMock - ->expects($this->at(0)) - ->method('loadLocationChildren') - ->with($this->equalTo($this->location)) - ->willReturn($this->locationChildren); - - $this->locationServiceMock - ->expects($this->at(1)) - ->method('loadLocationChildren') - ->with($this->equalTo($this->location1)) - ->willReturn($this->emptyLocationChildren); + $this->queryFactoryMock + ->method('create') + ->willReturn(new LocationQuery()); + + $this->searchServiceMock + ->method('findLocations') + ->willReturnOnConsecutiveCalls( + new SearchResult([ + 'searchHits' => [ + new SearchHit(['valueObject' => $this->location1]), + new SearchHit(['valueObject' => $this->location2]), + ], + ]), + new SearchResult([]), + new SearchResult([]) + ); $this->locationServiceMock - ->expects($this->at(2)) + ->expects(self::at(0)) ->method('loadLocation') ->with($this->equalTo($this->location1->id)) ->willReturn($this->location1); $this->locationServiceMock - ->expects($this->at(3)) - ->method('loadLocationChildren') - ->with($this->equalTo($this->location2)) - ->willReturn($this->emptyLocationChildren); - - $this->locationServiceMock - ->expects($this->at(4)) + ->expects(self::at(1)) ->method('loadLocation') ->with($this->equalTo($this->location2->id)) ->willReturn($this->location2); $this->locationServiceMock - ->expects($this->at(5)) + ->expects(self::at(2)) ->method('loadLocation') ->with($this->equalTo($this->location->id)) ->willReturn($this->location); + $content1 = new Content([ + 'versionInfo' => new VersionInfo([ + 'contentInfo' => new ContentInfo([ + 'id' => self::CONTENT_ID + 1, + 'contentTypeId' => self::CONTENT_TYPE_ID, + ]), + ]), + 'internalFields' => [], + ]); $this->contentHelperMock - ->expects($this->at(0)) + ->expects(self::at(0)) ->method('getIncludedContent') ->with($this->equalTo(self::CONTENT_ID + 1)) - ->willReturn(new Content([ - 'versionInfo' => new VersionInfo([ - 'contentInfo' => new ContentInfo([ - 'id' => self::CONTENT_ID + 1, - 'contentTypeId' => self::CONTENT_TYPE_ID, - ]), - ]), - 'internalFields' => [], - ])); + ->willReturn($content1); + $content2 = new Content([ + 'versionInfo' => new VersionInfo([ + 'contentInfo' => new ContentInfo([ + 'id' => self::CONTENT_ID + 2, + 'contentTypeId' => self::CONTENT_TYPE_ID, + ]), + ]), + 'internalFields' => [], + ]); $this->contentHelperMock - ->expects($this->at(1)) + ->expects(self::at(1)) ->method('getIncludedContent') ->with($this->equalTo(3)) - ->willReturn(new Content([ - 'versionInfo' => new VersionInfo([ - 'contentInfo' => new ContentInfo([ - 'id' => self::CONTENT_ID + 2, - 'contentTypeId' => self::CONTENT_TYPE_ID, - ]), - ]), - 'internalFields' => [], - ])); + ->willReturn($content2); $this->contentHelperMock - ->expects($this->at(2)) + ->expects(self::at(2)) ->method('getIncludedContent') ->with($this->equalTo(self::CONTENT_ID)) ->willReturn($this->content); + $this->notificationServiceMock + ->expects(self::exactly(3)) + ->method('sendNotification') + ->withConsecutive( + [ + $expectedNotificationMethod, + $expectedNotificationType, + $content1->contentInfo, + ], + [ + $expectedNotificationMethod, + $expectedNotificationType, + $content2->contentInfo, + ], + [ + $expectedNotificationMethod, + $expectedNotificationType, + $this->content->contentInfo, + ] + ); + $this->locationEventSubscriber->$method($eventMock); } + /** + * @return array + */ public function updateLocationWithChildrenDataProvider(): array { return [ - [HideLocationEvent::class, 'onHideLocation'], - [UnhideLocationEvent::class, 'onUnhideLocation'], + [ + HideLocationEvent::class, + 'onHideLocation', + 'EzSystems\EzRecommendationClient\Event\Subscriber\LocationEventSubscriber::hideLocation', + 'DELETE', + ], + [ + UnhideLocationEvent::class, + 'onUnhideLocation', + 'EzSystems\EzRecommendationClient\Event\Subscriber\LocationEventSubscriber::onUnhideLocation', + 'UPDATE', + ], ]; } } diff --git a/tests/lib/Event/Subscriber/TrashEventSubscriberTest.php b/tests/lib/Event/Subscriber/TrashEventSubscriberTest.php index 356d0b56..1b627187 100644 --- a/tests/lib/Event/Subscriber/TrashEventSubscriberTest.php +++ b/tests/lib/Event/Subscriber/TrashEventSubscriberTest.php @@ -12,7 +12,9 @@ use eZ\Publish\API\Repository\Events\Trash\TrashEvent; use eZ\Publish\API\Repository\Repository; use eZ\Publish\API\Repository\Values\Content\ContentInfo; -use eZ\Publish\API\Repository\Values\Content\LocationList; +use eZ\Publish\API\Repository\Values\Content\LocationQuery; +use eZ\Publish\API\Repository\Values\Content\Search\SearchHit; +use eZ\Publish\API\Repository\Values\Content\Search\SearchResult; use eZ\Publish\Core\Repository\Values\Content\Location; use eZ\Publish\Core\Repository\Values\Content\Relation; use EzSystems\EzRecommendationClient\Event\Subscriber\TrashEventSubscriber; @@ -39,6 +41,8 @@ public function setUp(): void $this->locationServiceMock, $this->locationHelperMock, $this->contentHelperMock, + $this->queryFactoryMock, + $this->searchServiceMock, $this->repositoryMock ); } @@ -63,55 +67,124 @@ public function subscribedEventsDataProvider(): array public function testCallOnTrashMethod() { + $relationContentInfo1 = new ContentInfo(['id' => 1, 'contentTypeId' => 2]); + $relationContentInfo2 = new ContentInfo(['id' => 2, 'contentTypeId' => 2]); + $relationContentInfo3 = new ContentInfo(['id' => 3, 'contentTypeId' => 3]); + $event = $this->createMock(TrashEvent::class); $event - ->expects($this->atLeastOnce()) + ->expects(self::atLeastOnce()) ->method('getLocation') ->willReturn($this->location); - $contentInfo = $this->contentInfo; $this->repositoryMock ->method('sudo') - ->with(static function () use ($contentInfo) {}) ->willReturn($this->getRelationList()); $this->contentServiceMock - ->expects($this->atLeastOnce()) + ->expects(self::atLeastOnce()) ->method('loadContentInfo') - ->willReturn($this->contentInfo); + ->willReturnOnConsecutiveCalls( + $relationContentInfo1, + $relationContentInfo2, + $relationContentInfo3, + ); + + $this->notificationServiceMock + ->expects(self::exactly(4)) + ->method('sendNotification') + ->withConsecutive( + [ + 'EzSystems\EzRecommendationClient\Event\Subscriber\TrashEventSubscriber::onTrash', + 'DELETE', + $this->contentInfo, + ], + [ + 'EzSystems\EzRecommendationClient\Event\Subscriber\TrashEventSubscriber::updateRelations', + 'UPDATE', + $relationContentInfo1, + ], + [ + 'EzSystems\EzRecommendationClient\Event\Subscriber\TrashEventSubscriber::updateRelations', + 'UPDATE', + $relationContentInfo2, + ], + [ + 'EzSystems\EzRecommendationClient\Event\Subscriber\TrashEventSubscriber::updateRelations', + 'UPDATE', + $relationContentInfo3, + ], + ); $this->trashEventSubscriber->onTrash($event); } public function testCallOnRecoverMethod() { + $relationContentInfo1 = new ContentInfo(['id' => 1, 'contentTypeId' => 2]); + $relationContentInfo2 = new ContentInfo(['id' => 2, 'contentTypeId' => 2]); + $relationContentInfo3 = new ContentInfo(['id' => 3, 'contentTypeId' => 3]); + + $locationContentInfo1 = new ContentInfo(['id' => self::CONTENT_ID + 1]); + $locationContentInfo2 = new ContentInfo(['id' => self::CONTENT_ID + 2]); + $event = $this->createMock(RecoverEvent::class); $event - ->expects($this->atLeastOnce()) + ->expects(self::atLeastOnce()) ->method('getLocation') ->willReturn($this->location); - $this->locationServiceMock - ->expects($this->atLeastOnce()) - ->method('loadLocationChildren') - ->with($this->location) - ->willReturn($this->getLocationChildren()); + $this->queryFactoryMock + ->method('create') + ->willReturn(new LocationQuery()); + + $this->searchServiceMock + ->method('findLocations') + ->willReturn($this->getLocationChildrenSearchResult()); $this->contentServiceMock - ->expects($this->atLeastOnce()) + ->expects(self::atLeastOnce()) ->method('loadContentInfo') - ->willReturn($this->contentInfo); + ->willReturnOnConsecutiveCalls( + $relationContentInfo1, + $relationContentInfo2, + $relationContentInfo3, + ); - $contentInfo = $this->contentInfo; $this->repositoryMock ->method('sudo') - ->with(static function () use ($contentInfo) {}) ->willReturn($this->getRelationList()); - $this->contentServiceMock - ->expects($this->atLeastOnce()) - ->method('loadContentInfo') - ->willReturn($this->contentInfo); + $this->notificationServiceMock + ->expects(self::exactly(5)) + ->method('sendNotification') + ->withConsecutive( + [ + 'EzSystems\EzRecommendationClient\Event\Subscriber\TrashEventSubscriber::onRecover', + 'UPDATE', + $locationContentInfo1, + ], + [ + 'EzSystems\EzRecommendationClient\Event\Subscriber\TrashEventSubscriber::onRecover', + 'UPDATE', + $locationContentInfo2, + ], + [ + 'EzSystems\EzRecommendationClient\Event\Subscriber\TrashEventSubscriber::updateRelations', + 'UPDATE', + $relationContentInfo1, + ], + [ + 'EzSystems\EzRecommendationClient\Event\Subscriber\TrashEventSubscriber::updateRelations', + 'UPDATE', + $relationContentInfo2, + ], + [ + 'EzSystems\EzRecommendationClient\Event\Subscriber\TrashEventSubscriber::updateRelations', + 'UPDATE', + $relationContentInfo3, + ], + ); $this->trashEventSubscriber->onRecover($event); } @@ -143,21 +216,20 @@ private function getReverseRelations(): array ]; } - private function getLocationChildren(): LocationList + private function getLocationChildrenSearchResult(): SearchResult { - return new LocationList([ - 'totalCount' => 2, - 'locations' => [ - new Location([ + return new SearchResult([ + 'searchHits' => [ + new SearchHit(['valueObject' => new Location([ 'id' => 20, 'path' => ['1', '5', '20'], 'contentInfo' => new ContentInfo(['id' => self::CONTENT_ID + 1]), - ]), - new Location([ + ])]), + new SearchHit(['valueObject' => new Location([ 'id' => 30, 'path' => ['1', '5', '30'], 'contentInfo' => new ContentInfo(['id' => self::CONTENT_ID + 2]), - ]), + ])]), ], ]); }