diff --git a/app/code/Magento/CompareListGraphQl/Model/Resolver/AddProductsToCompareList.php b/app/code/Magento/CompareListGraphQl/Model/Resolver/AddProductsToCompareList.php index 92c2bc1ab0551..b1d3baced670a 100644 --- a/app/code/Magento/CompareListGraphQl/Model/Resolver/AddProductsToCompareList.php +++ b/app/code/Magento/CompareListGraphQl/Model/Resolver/AddProductsToCompareList.php @@ -1,16 +1,19 @@ addProductToCompareList = $addProductToCompareList; $this->getCompareList = $getCompareList; $this->maskedListIdToCompareListId = $maskedListIdToCompareListId; $this->getListIdByCustomerId = $getListIdByCustomerId; + $this->productCompareHelper = $productCompareHelper ?: ObjectManager::getInstance() + ->get(Compare::class); + $this->compareCookieManager = $compareCookieManager ?: ObjectManager::getInstance() + ->get(CompareCookieManager::class); } /** @@ -97,13 +120,14 @@ public function resolve( throw new GraphQlInputException(__($exception->getMessage())); } - if (!$listId) { throw new GraphQlInputException(__('"uid" value does not exist')); } try { $this->addProductToCompareList->execute($listId, $args['input']['products'], $context); + $this->productCompareHelper->calculate(); + $this->compareCookieManager->invalidate(); } catch (\Exception $exception) { throw new GraphQlInputException(__($exception->getMessage())); } diff --git a/app/code/Magento/CompareListGraphQl/Model/Resolver/CreateCompareList.php b/app/code/Magento/CompareListGraphQl/Model/Resolver/CreateCompareList.php index 546bd3ee77096..271cdd4e4083c 100644 --- a/app/code/Magento/CompareListGraphQl/Model/Resolver/CreateCompareList.php +++ b/app/code/Magento/CompareListGraphQl/Model/Resolver/CreateCompareList.php @@ -1,16 +1,19 @@ mathRandom = $mathRandom; $this->getListIdByCustomerId = $getListIdByCustomerId; $this->addProductToCompareList = $addProductToCompareList; $this->getCompareList = $getCompareList; $this->createCompareList = $createCompareList; + $this->productCompareHelper = $productCompareHelper ?: ObjectManager::getInstance() + ->get(Compare::class); + $this->compareCookieManager = $compareCookieManager ?: ObjectManager::getInstance() + ->get(CompareCookieManager::class); } /** @@ -111,6 +134,8 @@ public function resolve( } else { $listId = $this->createCompareList->execute($generatedListId, $customerId); $this->addProductToCompareList->execute($listId, $products, $context); + $this->productCompareHelper->calculate(); + $this->compareCookieManager->invalidate(); } } } catch (LocalizedException $exception) { diff --git a/app/code/Magento/CompareListGraphQl/Model/Resolver/RemoveProductsFromCompareList.php b/app/code/Magento/CompareListGraphQl/Model/Resolver/RemoveProductsFromCompareList.php index fcfde3408ae44..bfb3e13f439cc 100644 --- a/app/code/Magento/CompareListGraphQl/Model/Resolver/RemoveProductsFromCompareList.php +++ b/app/code/Magento/CompareListGraphQl/Model/Resolver/RemoveProductsFromCompareList.php @@ -1,16 +1,19 @@ getCompareList = $getCompareList; $this->removeFromCompareList = $removeFromCompareList; $this->maskedListIdToCompareListId = $maskedListIdToCompareListId; $this->getListIdByCustomerId = $getListIdByCustomerId; + $this->productCompareHelper = $productCompareHelper ?: ObjectManager::getInstance() + ->get(Compare::class); + $this->compareCookieManager = $compareCookieManager ?: ObjectManager::getInstance() + ->get(CompareCookieManager::class); } /** @@ -111,6 +134,8 @@ public function resolve( try { $this->removeFromCompareList->execute($listId, $args['input']['products']); + $this->productCompareHelper->calculate(); + $this->compareCookieManager->invalidate(); } catch (LocalizedException $exception) { throw new GraphQlInputException( __('Something was wrong during removing products from compare list') diff --git a/app/code/Magento/CompareListGraphQl/Model/Service/CompareCookieManager.php b/app/code/Magento/CompareListGraphQl/Model/Service/CompareCookieManager.php new file mode 100644 index 0000000000000..ef68682912ed0 --- /dev/null +++ b/app/code/Magento/CompareListGraphQl/Model/Service/CompareCookieManager.php @@ -0,0 +1,106 @@ +cookieManager = $cookieManager; + $this->cookieMetadataFactory = $cookieMetadataFactory; + $this->logger = $logger; + } + + /** + * Marks compare products section as invalid by updating the cookie value + * + * @return void + */ + public function invalidate(): void + { + try { + $cookieValue = json_encode(['compare-products' => time()]); + $this->setCookie($cookieValue); + } catch (\Exception $e) { + $this->logger->error('Error invalidating compare products cookie: ' . $e->getMessage()); + } + } + + /** + * Set compare products cookie + * + * @param string $value + * @return void + * @throws InputException + * @throws CookieSizeLimitReachedException + * @throws FailureToSendException + */ + private function setCookie(string $value): void + { + $publicCookieMetadata = $this->cookieMetadataFactory->createPublicCookieMetadata() + ->setDuration(self::COOKIE_LIFETIME) + ->setPath(self::COOKIE_PATH) + ->setHttpOnly(false); + + $this->cookieManager->setPublicCookie( + self::COOKIE_COMPARE_PRODUCTS, + $value, + $publicCookieMetadata + ); + } +} diff --git a/app/code/Magento/CompareListGraphQl/Test/Unit/Model/Service/CompareCookieManagerTest.php b/app/code/Magento/CompareListGraphQl/Test/Unit/Model/Service/CompareCookieManagerTest.php new file mode 100644 index 0000000000000..2bb067a8c5c51 --- /dev/null +++ b/app/code/Magento/CompareListGraphQl/Test/Unit/Model/Service/CompareCookieManagerTest.php @@ -0,0 +1,231 @@ +cookieManagerMock = $this->getMockForAbstractClass(CookieManagerInterface::class); + $this->cookieMetadataFactoryMock = $this->createMock(CookieMetadataFactory::class); + $this->loggerMock = $this->getMockForAbstractClass(LoggerInterface::class); + $this->publicCookieMetadataMock = $this->createMock(PublicCookieMetadata::class); + + $this->compareCookieManager = new CompareCookieManager( + $this->cookieManagerMock, + $this->cookieMetadataFactoryMock, + $this->loggerMock + ); + } + + /** + * Test invalidate method successfully sets cookie + * + * @return void + */ + public function testInvalidateSuccess(): void + { + $this->cookieMetadataFactoryMock->expects($this->once()) + ->method('createPublicCookieMetadata') + ->willReturn($this->publicCookieMetadataMock); + + $this->publicCookieMetadataMock->expects($this->once()) + ->method('setDuration') + ->with(CompareCookieManager::COOKIE_LIFETIME) + ->willReturnSelf(); + + $this->publicCookieMetadataMock->expects($this->once()) + ->method('setPath') + ->with(CompareCookieManager::COOKIE_PATH) + ->willReturnSelf(); + + $this->publicCookieMetadataMock->expects($this->once()) + ->method('setHttpOnly') + ->with(false) + ->willReturnSelf(); + + $this->cookieManagerMock->expects($this->once()) + ->method('setPublicCookie') + ->with( + CompareCookieManager::COOKIE_COMPARE_PRODUCTS, + $this->callback(function ($value) { + $decodedValue = json_decode($value, true); + return isset($decodedValue['compare-products']) && is_int($decodedValue['compare-products']); + }), + $this->publicCookieMetadataMock + ); + + $this->compareCookieManager->invalidate(); + } + + /** + * Test invalidate method logs exception when cookie setting fails + * + * @return void + */ + public function testInvalidateWithException(): void + { + $exception = new InputException(__('Error setting cookie')); + + $this->cookieMetadataFactoryMock->expects($this->once()) + ->method('createPublicCookieMetadata') + ->willReturn($this->publicCookieMetadataMock); + + $this->publicCookieMetadataMock->expects($this->once()) + ->method('setDuration') + ->willReturnSelf(); + + $this->publicCookieMetadataMock->expects($this->once()) + ->method('setPath') + ->willReturnSelf(); + + $this->publicCookieMetadataMock->expects($this->once()) + ->method('setHttpOnly') + ->willReturnSelf(); + + $this->cookieManagerMock->expects($this->once()) + ->method('setPublicCookie') + ->willThrowException($exception); + + $this->loggerMock->expects($this->once()) + ->method('error') + ->with($this->stringContains('Error invalidating compare products cookie')); + + $this->compareCookieManager->invalidate(); + } + + /** + * Test cookie creation with CookieSizeLimitReachedException + * + * @return void + */ + public function testInvalidateWithCookieSizeLimitReachedException(): void + { + $exception = new CookieSizeLimitReachedException(__('Cookie size limit reached')); + + $this->cookieMetadataFactoryMock->expects($this->once()) + ->method('createPublicCookieMetadata') + ->willReturn($this->publicCookieMetadataMock); + + $this->publicCookieMetadataMock->expects($this->once()) + ->method('setDuration') + ->willReturnSelf(); + + $this->publicCookieMetadataMock->expects($this->once()) + ->method('setPath') + ->willReturnSelf(); + + $this->publicCookieMetadataMock->expects($this->once()) + ->method('setHttpOnly') + ->willReturnSelf(); + + $this->cookieManagerMock->expects($this->once()) + ->method('setPublicCookie') + ->willThrowException($exception); + + $this->loggerMock->expects($this->once()) + ->method('error') + ->with($this->stringContains('Error invalidating compare products cookie')); + + $this->compareCookieManager->invalidate(); + } + + /** + * Test cookie creation with FailureToSendException + * + * @return void + */ + public function testInvalidateWithFailureToSendException(): void + { + $exception = new FailureToSendException(__('Failed to send cookie')); + + $this->cookieMetadataFactoryMock->expects($this->once()) + ->method('createPublicCookieMetadata') + ->willReturn($this->publicCookieMetadataMock); + + $this->publicCookieMetadataMock->expects($this->once()) + ->method('setDuration') + ->willReturnSelf(); + + $this->publicCookieMetadataMock->expects($this->once()) + ->method('setPath') + ->willReturnSelf(); + + $this->publicCookieMetadataMock->expects($this->once()) + ->method('setHttpOnly') + ->willReturnSelf(); + + $this->cookieManagerMock->expects($this->once()) + ->method('setPublicCookie') + ->willThrowException($exception); + + $this->loggerMock->expects($this->once()) + ->method('error') + ->with($this->stringContains('Error invalidating compare products cookie')); + + $this->compareCookieManager->invalidate(); + } + + /** + * Test that constants have the expected values + * + * @return void + */ + public function testConstants(): void + { + $this->assertEquals('section_data_ids', CompareCookieManager::COOKIE_COMPARE_PRODUCTS); + $this->assertEquals('/', CompareCookieManager::COOKIE_PATH); + $this->assertEquals(86400, CompareCookieManager::COOKIE_LIFETIME); + } +}