From dcc5db237a39db7862ce9650a5368be8b3f9c390 Mon Sep 17 00:00:00 2001 From: Stanislav Ilnytskyi Date: Sat, 2 Oct 2021 14:54:09 +0200 Subject: [PATCH 01/10] MAGETWO-99236 Fix for #22063 --- app/code/Magento/Catalog/Model/CategoryLinkRepository.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Catalog/Model/CategoryLinkRepository.php b/app/code/Magento/Catalog/Model/CategoryLinkRepository.php index f8de9a37f4ed7..74a5c0e29b715 100644 --- a/app/code/Magento/Catalog/Model/CategoryLinkRepository.php +++ b/app/code/Magento/Catalog/Model/CategoryLinkRepository.php @@ -11,6 +11,7 @@ use Magento\Catalog\Api\CategoryRepositoryInterface; use Magento\Catalog\Api\ProductRepositoryInterface; use Magento\Catalog\Model\ResourceModel\Product; +use Magento\Store\Model\Store; use Magento\Framework\App\ObjectManager; use Magento\Framework\Exception\CouldNotSaveException; use Magento\Framework\Exception\InputException; @@ -55,7 +56,7 @@ public function __construct( */ public function save(\Magento\Catalog\Api\Data\CategoryProductLinkInterface $productLink) { - $category = $this->categoryRepository->get($productLink->getCategoryId()); + $category = $this->categoryRepository->get($productLink->getCategoryId(), Store::DEFAULT_STORE_ID); $product = $this->productRepository->get($productLink->getSku()); $productPositions = $category->getProductsPosition(); $productPositions[$product->getId()] = $productLink->getPosition(); @@ -89,7 +90,7 @@ public function delete(\Magento\Catalog\Api\Data\CategoryProductLinkInterface $p */ public function deleteByIds($categoryId, $sku) { - $category = $this->categoryRepository->get($categoryId); + $category = $this->categoryRepository->get($categoryId, Store::DEFAULT_STORE_ID); $product = $this->productRepository->get($sku); $productPositions = $category->getProductsPosition(); @@ -124,7 +125,7 @@ public function deleteByIds($categoryId, $sku) */ public function deleteBySkus(int $categoryId, array $productSkuList): bool { - $category = $this->categoryRepository->get($categoryId); + $category = $this->categoryRepository->get($categoryId, Store::DEFAULT_STORE_ID); $products = $this->productResource->getProductsIdsBySkus($productSkuList); if (!$products) { From a12a2b9342cf80b5e014c7f037eabdf0d8ecd431 Mon Sep 17 00:00:00 2001 From: Stanislav Ilnytskyi Date: Sat, 2 Oct 2021 21:18:39 +0200 Subject: [PATCH 02/10] #22063 add test, fix failing test --- .../Catalog/Model/ResourceModel/Category.php | 2 +- .../Model/CategoryLinkRepositoryTest.php | 99 +++++++++++++++++++ ...t_category_link_under_different_stores.php | 75 ++++++++++++++ 3 files changed, 175 insertions(+), 1 deletion(-) create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/Model/CategoryLinkRepositoryTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/_files/saving_product_category_link_under_different_stores.php diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Category.php b/app/code/Magento/Catalog/Model/ResourceModel/Category.php index 18f38f7d2bc24..e273f1bbc72ad 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Category.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Category.php @@ -447,7 +447,7 @@ protected function _saveCategoryProducts($category) 'position' => (int)$position, ]; } - $connection->insertMultiple($this->getCategoryProductTable(), $data); + $connection->insertOnDuplicate($this->getCategoryProductTable(), $data, ['position']); } /** diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/CategoryLinkRepositoryTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/CategoryLinkRepositoryTest.php new file mode 100644 index 0000000000000..8ea62e04ef3c7 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/CategoryLinkRepositoryTest.php @@ -0,0 +1,99 @@ +objectManager = Bootstrap::getObjectManager(); + $this->categoryLinkRepository = $this->objectManager->get(CategoryLinkRepositoryInterface::class); + $this->storeRepository = $this->objectManager->get(StoreRepositoryInterface::class); + $this->categoryRepository = $this->objectManager->get(CategoryRepositoryInterface::class); + $this->appEmulation = $this->objectManager->get(Emulation::class); + parent::setUp(); + } + + /** + * Make sure that if some custom code uses emulation and assigns products to categories, + * the categories are not overwritten by loading data via category repository from wrong store. + * The default store is used in + * @see \Magento\Catalog\Model\CategoryLinkRepository::save + * + * @magentoAppArea crontab + * @magentoDbIsolation disabled + * @magentoDataFixture Magento/Catalog/_files/saving_product_category_link_under_different_stores.php + */ + public function testCategoryDataNotChanged() + { + $secondStore = $this->storeRepository->get('fixture_second_store'); + $secondStoreId = (int)$secondStore->getId(); + /** @var CategoryProductLinkInterface $categoryProductLink */ + $categoryProductLink = $this->objectManager->create(CategoryProductLinkInterface::class); + + $this->appEmulation->startEnvironmentEmulation($secondStoreId, Area::AREA_FRONTEND, true); + + $categoryProductLink + ->setCategoryId(113) + ->setSku('simple116') + ->setPosition(2); + + $this->categoryLinkRepository->save($categoryProductLink); + + $this->appEmulation->stopEnvironmentEmulation(); + + $categoryFromDefaultStore = $this->categoryRepository->get(113); + $categoryFromSecondStore = $this->categoryRepository->get(113, $secondStoreId); + + $categoryNameFromDefaultStore = $categoryFromDefaultStore->getName(); + $categoryDescriptionFromDefaultStore = $categoryFromDefaultStore->getDescription(); + + $categoryNameFromSecondStore = $categoryFromSecondStore->getName(); + $categoryDescriptionFromSecondStore = $categoryFromSecondStore->getDescription(); + + $this->assertEquals('Test Category In Default Store', $categoryNameFromDefaultStore); + $this->assertEquals('Test description in default store', $categoryDescriptionFromDefaultStore); + $this->assertEquals('Test Category In Second Store', $categoryNameFromSecondStore); + $this->assertEquals('Test description in second store', $categoryDescriptionFromSecondStore); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/saving_product_category_link_under_different_stores.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/saving_product_category_link_under_different_stores.php new file mode 100644 index 0000000000000..9cf6353de3c44 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/saving_product_category_link_under_different_stores.php @@ -0,0 +1,75 @@ +requireDataFixture('Magento/Store/_files/second_store.php'); + +$objectManager = Bootstrap::getObjectManager(); + +/** @var StoreInterface $defaultWebsite */ +$defaultStoreView = $objectManager->get(StoreManagerInterface::class)->getDefaultStoreView(); + +/** @var StoreRepositoryInterface $storeRepository */ +$storeRepository = $objectManager->get(StoreRepositoryInterface::class); +$secondStore = $storeRepository->get('fixture_second_store'); + +/** @var CategoryResource $categoryResource */ +$categoryResource = $objectManager->get(CategoryResource::class); + +/** @var ProductResource $productResource */ +$productResource = $objectManager->get(ProductResource::class); + +/** @var CategoryInterface|Category $category */ +$category = $objectManager->create(CategoryInterface::class); +$category->isObjectNew(true); +$category + ->setId(113) + ->setIsAnchor(true) + ->setStoreId($defaultStoreView->getId()) + ->setName('Test Category In Default Store') + ->setDescription('Test description in default store') + ->setParentId(2) + ->setPath('1/2/113') + ->setLevel(2) + ->setAvailableSortBy('name') + ->setDefaultSortBy('name') + ->setIsActive(true); +$categoryResource->save($category); + +$category + ->setStoreId($secondStore->getId()) + ->setName('Test Category In Second Store') + ->setDescription('Test description in second store'); +$categoryResource->save($category); + +/** @var Product $product */ +$product = $objectManager->create(Product::class); +$product + ->setTypeId('simple') + ->setId(116) + ->setAttributeSetId(4) + ->setWebsiteIds([$defaultStoreView->getWebsiteId()]) + ->setName('Simple Product116') + ->setSku('simple116') + ->setPrice(10) + ->setMetaTitle('meta title2') + ->setMetaKeyword('meta keyword2') + ->setMetaDescription('meta description2') + ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH) + ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED) + ->setStockData(['use_config_manage_stock' => 0]); +$productResource->save($product); From a814b6c5d13c47ce36224a96b292a01a1c80bdaf Mon Sep 17 00:00:00 2001 From: Stanislav Ilnytskyi Date: Sun, 3 Oct 2021 17:32:27 +0200 Subject: [PATCH 03/10] #22063 Improve Category repository, improve performance of saving link, improve test case, improve test fixtures --- .../Catalog/Model/CategoryLinkRepository.php | 20 +++++------ .../Catalog/Model/CategoryRepository.php | 2 +- .../Model/CategoryLinkRepositoryTest.php | 1 + ...t_category_link_under_different_stores.php | 10 ++---- ...y_link_under_different_stores_rollback.php | 35 +++++++++++++++++++ 5 files changed, 50 insertions(+), 18 deletions(-) create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/_files/saving_product_category_link_under_different_stores_rollback.php diff --git a/app/code/Magento/Catalog/Model/CategoryLinkRepository.php b/app/code/Magento/Catalog/Model/CategoryLinkRepository.php index 74a5c0e29b715..58a6da64b79c5 100644 --- a/app/code/Magento/Catalog/Model/CategoryLinkRepository.php +++ b/app/code/Magento/Catalog/Model/CategoryLinkRepository.php @@ -27,6 +27,7 @@ class CategoryLinkRepository implements CategoryLinkRepositoryInterface, Categor protected $categoryRepository; /** + * @deprecated * @var ProductRepositoryInterface */ protected $productRepository; @@ -56,10 +57,10 @@ public function __construct( */ public function save(\Magento\Catalog\Api\Data\CategoryProductLinkInterface $productLink) { - $category = $this->categoryRepository->get($productLink->getCategoryId(), Store::DEFAULT_STORE_ID); - $product = $this->productRepository->get($productLink->getSku()); + $category = $this->categoryRepository->get($productLink->getCategoryId()); + $productId = $this->productResource->getIdBySku($productLink->getSku()); $productPositions = $category->getProductsPosition(); - $productPositions[$product->getId()] = $productLink->getPosition(); + $productPositions[$productId] = $productLink->getPosition(); $category->setPostedProducts($productPositions); try { $category->save(); @@ -67,7 +68,7 @@ public function save(\Magento\Catalog\Api\Data\CategoryProductLinkInterface $pro throw new CouldNotSaveException( __( 'Could not save product "%1" with position %2 to category %3', - $product->getId(), + $productId, $productLink->getPosition(), $category->getId() ), @@ -91,15 +92,14 @@ public function delete(\Magento\Catalog\Api\Data\CategoryProductLinkInterface $p public function deleteByIds($categoryId, $sku) { $category = $this->categoryRepository->get($categoryId, Store::DEFAULT_STORE_ID); - $product = $this->productRepository->get($sku); + $productId = $this->productResource->getIdBySku($sku); $productPositions = $category->getProductsPosition(); - $productID = $product->getId(); - if (!isset($productPositions[$productID])) { + if (!isset($productPositions[$productId])) { throw new InputException(__("The category doesn't contain the specified product.")); } - $backupPosition = $productPositions[$productID]; - unset($productPositions[$productID]); + $backupPosition = $productPositions[$productId]; + unset($productPositions[$productId]); $category->setPostedProducts($productPositions); try { @@ -109,7 +109,7 @@ public function deleteByIds($categoryId, $sku) __( 'Could not save product "%product" with position %position to category %category', [ - "product" => $product->getId(), + "product" => $productId, "position" => $backupPosition, "category" => $category->getId() ] diff --git a/app/code/Magento/Catalog/Model/CategoryRepository.php b/app/code/Magento/Catalog/Model/CategoryRepository.php index 7082fa4747fdc..9a6d007c58c08 100644 --- a/app/code/Magento/Catalog/Model/CategoryRepository.php +++ b/app/code/Magento/Catalog/Model/CategoryRepository.php @@ -147,7 +147,7 @@ public function save(CategoryInterface $category) */ public function get($categoryId, $storeId = null) { - $cacheKey = $storeId ?? 'all'; + $cacheKey = $storeId ?? $this->storeManager->getStore()->getId(); if (!isset($this->instances[$categoryId][$cacheKey])) { /** @var Category $category */ $category = $this->categoryFactory->create(); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/CategoryLinkRepositoryTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/CategoryLinkRepositoryTest.php index 8ea62e04ef3c7..3d89db8508040 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/CategoryLinkRepositoryTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/CategoryLinkRepositoryTest.php @@ -13,6 +13,7 @@ use Magento\Framework\App\Area; use Magento\Store\Api\StoreRepositoryInterface; use Magento\Store\Model\App\Emulation; +use Magento\Store\Model\Store; use Magento\TestFramework\Helper\Bootstrap; use Magento\TestFramework\ObjectManager; use PHPUnit\Framework\TestCase; diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/saving_product_category_link_under_different_stores.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/saving_product_category_link_under_different_stores.php index 9cf6353de3c44..0b99750a6e9f8 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/_files/saving_product_category_link_under_different_stores.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/saving_product_category_link_under_different_stores.php @@ -11,8 +11,7 @@ use Magento\Catalog\Model\ResourceModel\Category as CategoryResource; use Magento\Catalog\Model\ResourceModel\Product as ProductResource; use Magento\Store\Api\StoreRepositoryInterface; -use Magento\Store\Api\Data\StoreInterface; -use Magento\Store\Model\StoreManagerInterface; +use Magento\Store\Model\Store; use Magento\TestFramework\Helper\Bootstrap; use Magento\TestFramework\Workaround\Override\Fixture\Resolver; @@ -20,9 +19,6 @@ $objectManager = Bootstrap::getObjectManager(); -/** @var StoreInterface $defaultWebsite */ -$defaultStoreView = $objectManager->get(StoreManagerInterface::class)->getDefaultStoreView(); - /** @var StoreRepositoryInterface $storeRepository */ $storeRepository = $objectManager->get(StoreRepositoryInterface::class); $secondStore = $storeRepository->get('fixture_second_store'); @@ -39,7 +35,7 @@ $category ->setId(113) ->setIsAnchor(true) - ->setStoreId($defaultStoreView->getId()) + ->setStoreId(Store::DEFAULT_STORE_ID) ->setName('Test Category In Default Store') ->setDescription('Test description in default store') ->setParentId(2) @@ -62,7 +58,7 @@ ->setTypeId('simple') ->setId(116) ->setAttributeSetId(4) - ->setWebsiteIds([$defaultStoreView->getWebsiteId()]) + ->setWebsiteIds([$secondStore->getWebsiteId()]) ->setName('Simple Product116') ->setSku('simple116') ->setPrice(10) diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/saving_product_category_link_under_different_stores_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/saving_product_category_link_under_different_stores_rollback.php new file mode 100644 index 0000000000000..8cbd30093c57a --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/saving_product_category_link_under_different_stores_rollback.php @@ -0,0 +1,35 @@ +get(CategoryRepositoryInterface::class); + +/** @var ProductRepositoryInterface $productRepository */ +$productRepository = $objectManager->get(ProductRepositoryInterface::class); + +/** @var Registry $registry */ +$registry = $objectManager->get(Registry::class); + +$isSecurePreviousValue = $registry->registry('isSecureArea'); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +$productRepository->deleteById('simple116'); +$productRepository->cleanCache(); + +$categoryRepository->deleteByIdentifier(113); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', $isSecurePreviousValue); From b1fd10d464916419cf9ed7478bed8b789f1c3236 Mon Sep 17 00:00:00 2001 From: Stanislav Ilnytskyi Date: Sun, 3 Oct 2021 17:36:32 +0200 Subject: [PATCH 04/10] #22063 static test fix --- app/code/Magento/Catalog/Model/ResourceModel/Category.php | 6 ------ 1 file changed, 6 deletions(-) diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Category.php b/app/code/Magento/Catalog/Model/ResourceModel/Category.php index e273f1bbc72ad..69f0e72cc9138 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Category.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Category.php @@ -36,8 +36,6 @@ class Category extends AbstractResource protected $_tree; /** - * Catalog products table name - * * @var string */ protected $_categoryProductTable; @@ -48,15 +46,11 @@ class Category extends AbstractResource private $entitiesWhereAttributesIs; /** - * Id of 'is_active' category attribute - * * @var int */ protected $_isActiveAttributeId = null; /** - * Store id - * * @var int */ protected $_storeId = null; From f6d6f329b635319ebf300af626e75cb34c4cbee1 Mon Sep 17 00:00:00 2001 From: Stanislav Ilnytskyi Date: Sun, 3 Oct 2021 18:47:18 +0200 Subject: [PATCH 05/10] #22063 Static test fix --- app/code/Magento/Catalog/Model/CategoryRepository.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Catalog/Model/CategoryRepository.php b/app/code/Magento/Catalog/Model/CategoryRepository.php index 9a6d007c58c08..6c5319675ee6d 100644 --- a/app/code/Magento/Catalog/Model/CategoryRepository.php +++ b/app/code/Magento/Catalog/Model/CategoryRepository.php @@ -54,14 +54,14 @@ class CategoryRepository implements \Magento\Catalog\Api\CategoryRepositoryInter * @var ExtensibleDataObjectConverter */ private $extensibleDataObjectConverter; - + // @codingStandardsIgnoreStart /** - * List of fields that can used config values in case when value does not defined directly + * List of fields that can use config values in case when value does not defined directly * * @var array */ protected $useConfigFields = ['available_sort_by', 'default_sort_by', 'filter_price_range']; - + // @codingStandardsIgnoreEnd /** * @var PopulateWithValues */ From 30f54bbb0a031090a5897257714ab7c376223ff8 Mon Sep 17 00:00:00 2001 From: Stanislav Ilnytskyi Date: Sun, 3 Oct 2021 19:10:55 +0200 Subject: [PATCH 06/10] #22063 fix unit tests --- .../Catalog/Model/CategoryLinkRepository.php | 5 ++- .../Unit/Model/CategoryLinkRepositoryTest.php | 32 +++++-------------- 2 files changed, 10 insertions(+), 27 deletions(-) diff --git a/app/code/Magento/Catalog/Model/CategoryLinkRepository.php b/app/code/Magento/Catalog/Model/CategoryLinkRepository.php index 58a6da64b79c5..0ca80acafa657 100644 --- a/app/code/Magento/Catalog/Model/CategoryLinkRepository.php +++ b/app/code/Magento/Catalog/Model/CategoryLinkRepository.php @@ -11,7 +11,6 @@ use Magento\Catalog\Api\CategoryRepositoryInterface; use Magento\Catalog\Api\ProductRepositoryInterface; use Magento\Catalog\Model\ResourceModel\Product; -use Magento\Store\Model\Store; use Magento\Framework\App\ObjectManager; use Magento\Framework\Exception\CouldNotSaveException; use Magento\Framework\Exception\InputException; @@ -91,7 +90,7 @@ public function delete(\Magento\Catalog\Api\Data\CategoryProductLinkInterface $p */ public function deleteByIds($categoryId, $sku) { - $category = $this->categoryRepository->get($categoryId, Store::DEFAULT_STORE_ID); + $category = $this->categoryRepository->get($categoryId); $productId = $this->productResource->getIdBySku($sku); $productPositions = $category->getProductsPosition(); @@ -125,7 +124,7 @@ public function deleteByIds($categoryId, $sku) */ public function deleteBySkus(int $categoryId, array $productSkuList): bool { - $category = $this->categoryRepository->get($categoryId, Store::DEFAULT_STORE_ID); + $category = $this->categoryRepository->get($categoryId); $products = $this->productResource->getProductsIdsBySkus($productSkuList); if (!$products) { diff --git a/app/code/Magento/Catalog/Test/Unit/Model/CategoryLinkRepositoryTest.php b/app/code/Magento/Catalog/Test/Unit/Model/CategoryLinkRepositoryTest.php index 7089b1a0914a5..52c8631d10cf5 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/CategoryLinkRepositoryTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/CategoryLinkRepositoryTest.php @@ -12,7 +12,6 @@ use Magento\Catalog\Api\ProductRepositoryInterface; use Magento\Catalog\Model\Category; use Magento\Catalog\Model\CategoryLinkRepository; -use Magento\Catalog\Model\Product as ProductModel; use Magento\Catalog\Model\ResourceModel\Product; use Magento\Framework\Exception\CouldNotSaveException; use Magento\Framework\Exception\InputException; @@ -37,6 +36,7 @@ class CategoryLinkRepositoryTest extends TestCase private $categoryRepositoryMock; /** + * @deprecated * @var ProductRepositoryInterface|MockObject */ private $productRepositoryMock; @@ -58,7 +58,7 @@ protected function setUp(): void { $this->productResourceMock = $this->getMockBuilder(Product::class) ->disableOriginalConstructor() - ->setMethods(['getProductsIdsBySkus']) + ->onlyMethods(['getProductsIdsBySkus', 'getIdBySku']) ->getMock(); $this->categoryRepositoryMock = $this->getMockForAbstractClass(CategoryRepositoryInterface::class); $this->productRepositoryMock = $this->getMockForAbstractClass(ProductRepositoryInterface::class); @@ -87,14 +87,12 @@ public function testSave(): void ->onlyMethods(['getProductsPosition', 'save']) ->disableOriginalConstructor() ->getMock(); - $productMock = $this->createMock(ProductModel::class); $this->productLinkMock->expects($this->once())->method('getCategoryId')->willReturn($categoryId); $this->productLinkMock->expects($this->once())->method('getSku')->willReturn($sku); $this->categoryRepositoryMock->expects($this->once())->method('get')->with($categoryId) ->willReturn($categoryMock); - $this->productRepositoryMock->expects($this->once())->method('get')->with($sku)->willReturn($productMock); $categoryMock->expects($this->once())->method('getProductsPosition')->willReturn([]); - $productMock->expects($this->once())->method('getId')->willReturn($productId); + $this->productResourceMock->expects($this->once())->method('getIdBySku')->willReturn($productId); $this->productLinkMock->expects($this->once())->method('getPosition')->willReturn($productPosition); $categoryMock->expects($this->once())->method('setPostedProducts')->with($productPositions); $categoryMock->expects($this->once())->method('save'); @@ -119,14 +117,12 @@ public function testSaveWithCouldNotSaveException(): void ->onlyMethods(['getProductsPosition', 'save', 'getId']) ->disableOriginalConstructor() ->getMock(); - $productMock = $this->createMock(ProductModel::class); $this->productLinkMock->expects($this->once())->method('getCategoryId')->willReturn($categoryId); $this->productLinkMock->expects($this->once())->method('getSku')->willReturn($sku); $this->categoryRepositoryMock->expects($this->once())->method('get')->with($categoryId) ->willReturn($categoryMock); - $this->productRepositoryMock->expects($this->once())->method('get')->with($sku)->willReturn($productMock); $categoryMock->expects($this->once())->method('getProductsPosition')->willReturn([]); - $productMock->expects($this->exactly(2))->method('getId')->willReturn($productId); + $this->productResourceMock->expects($this->once())->method('getIdBySku')->willReturn($productId); $this->productLinkMock->expects($this->exactly(2))->method('getPosition')->willReturn($productPosition); $categoryMock->expects($this->once())->method('setPostedProducts')->with($productPositions); $categoryMock->expects($this->once())->method('getId')->willReturn($categoryId); @@ -153,13 +149,10 @@ public function testDeleteByIds(): void ->onlyMethods(['getProductsPosition', 'save', 'getId']) ->disableOriginalConstructor() ->getMock(); - $productMock = $this->createMock(ProductModel::class); $this->categoryRepositoryMock->expects($this->once())->method('get')->with($categoryId) ->willReturn($categoryMock); - $this->productRepositoryMock->expects($this->once())->method('get')->with($productSku) - ->willReturn($productMock); $categoryMock->expects($this->once())->method('getProductsPosition')->willReturn($productPositions); - $productMock->expects($this->once())->method('getId')->willReturn($productId); + $this->productResourceMock->expects($this->once())->method('getIdBySku')->willReturn($productId); $categoryMock->expects($this->once())->method('setPostedProducts')->with([]); $categoryMock->expects($this->once())->method('save'); @@ -182,13 +175,10 @@ public function testDeleteByIdsWithCouldNotSaveException(): void ->onlyMethods(['getProductsPosition', 'save', 'getId']) ->disableOriginalConstructor() ->getMock(); - $productMock = $this->createMock(ProductModel::class); $this->categoryRepositoryMock->expects($this->once())->method('get')->with($categoryId) ->willReturn($categoryMock); - $this->productRepositoryMock->expects($this->once())->method('get')->with($productSku) - ->willReturn($productMock); $categoryMock->expects($this->once())->method('getProductsPosition')->willReturn($productPositions); - $productMock->expects($this->exactly(2))->method('getId')->willReturn($productId); + $this->productResourceMock->expects($this->once())->method('getIdBySku')->willReturn($productId); $categoryMock->expects($this->once())->method('setPostedProducts')->with([]); $categoryMock->expects($this->once())->method('getId')->willReturn($categoryId); $categoryMock->expects($this->once())->method('save')->willThrowException(new \Exception()); @@ -216,13 +206,10 @@ public function testDeleteWithInputException(): void ->onlyMethods(['getProductsPosition', 'save', 'getId']) ->disableOriginalConstructor() ->getMock(); - $productMock = $this->createMock(ProductModel::class); $this->categoryRepositoryMock->expects($this->once())->method('get')->with($categoryId) ->willReturn($categoryMock); - $this->productRepositoryMock->expects($this->once())->method('get')->with($productSku) - ->willReturn($productMock); $categoryMock->expects($this->once())->method('getProductsPosition')->willReturn($productPositions); - $productMock->expects($this->once())->method('getId')->willReturn($productId); + $this->productResourceMock->expects($this->once())->method('getIdBySku')->willReturn($productId); $categoryMock->expects($this->never())->method('save'); $this->expectExceptionMessage('The category doesn\'t contain the specified product.'); @@ -248,13 +235,10 @@ public function testDelete(): void ->onlyMethods(['getProductsPosition', 'save', 'getId']) ->disableOriginalConstructor() ->getMock(); - $productMock = $this->createMock(ProductModel::class); $this->categoryRepositoryMock->expects($this->once())->method('get')->with($categoryId) ->willReturn($categoryMock); - $this->productRepositoryMock->expects($this->once())->method('get')->with($productSku) - ->willReturn($productMock); $categoryMock->expects($this->once())->method('getProductsPosition')->willReturn($productPositions); - $productMock->expects($this->once())->method('getId')->willReturn($productId); + $this->productResourceMock->expects($this->once())->method('getIdBySku')->willReturn($productId); $categoryMock->expects($this->once())->method('setPostedProducts')->with([]); $categoryMock->expects($this->once())->method('save'); From 7ee34dcc05739e53d3d4c2f6c15910bb36a1ce43 Mon Sep 17 00:00:00 2001 From: Stanislav Ilnytskyi Date: Sun, 3 Oct 2021 19:40:08 +0200 Subject: [PATCH 07/10] fixtures improve --- ...g_product_category_link_under_different_stores_rollback.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/saving_product_category_link_under_different_stores_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/saving_product_category_link_under_different_stores_rollback.php index 8cbd30093c57a..91c4c2217b73e 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/_files/saving_product_category_link_under_different_stores_rollback.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/saving_product_category_link_under_different_stores_rollback.php @@ -9,6 +9,7 @@ use Magento\Framework\Registry; use Magento\Catalog\Api\ProductRepositoryInterface; use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\Workaround\Override\Fixture\Resolver; $objectManager = Bootstrap::getObjectManager(); @@ -31,5 +32,7 @@ $categoryRepository->deleteByIdentifier(113); +Resolver::getInstance()->requireDataFixture('Magento/Store/_files/second_store_rollback.php'); + $registry->unregister('isSecureArea'); $registry->register('isSecureArea', $isSecurePreviousValue); From e10ae425b8262917d32364bb54d1b96e3a2cb838 Mon Sep 17 00:00:00 2001 From: Stanislav Ilnytskyi Date: Sun, 3 Oct 2021 20:08:29 +0200 Subject: [PATCH 08/10] #22063 fix cache in category tests --- .../Adminhtml/Category/Save/UpdateCategoryTest.php | 8 +++++++- .../Magento/Catalog/Controller/Adminhtml/CategoryTest.php | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Category/Save/UpdateCategoryTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Category/Save/UpdateCategoryTest.php index 75b96a1af3b09..e771426439060 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Category/Save/UpdateCategoryTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Category/Save/UpdateCategoryTest.php @@ -51,7 +51,13 @@ public function testUpdateCategoryForDefaultStoreView(array $postData): void $postData = array_merge($postData, ['store_id' => $storeId]); $responseData = $this->performSaveCategoryRequest($postData); $this->assertRequestIsSuccessfullyPerformed($responseData); - $category = $this->categoryRepository->get($postData['entity_id'], $postData['store_id']); + /** + * The problem is that + * @see \Magento\Catalog\Controller\Adminhtml\Category\Save::execute + * saves the category via resource model, so the cache in the repository is not cleaned + */ + $newCategoryRepository = $this->_objectManager->create(CategoryRepositoryInterface::class); + $category = $newCategoryRepository->get($postData['entity_id'], $postData['store_id']); unset($postData['use_default']); unset($postData['use_config']); foreach ($postData as $key => $value) { diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/CategoryTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/CategoryTest.php index eba80a0584fd4..4825598b26221 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/CategoryTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/CategoryTest.php @@ -177,7 +177,13 @@ public function testDefaultValueForCategoryUrlPath(): void $this->equalTo([(string)__('You saved the category.')]), MessageInterface::TYPE_SUCCESS ); - $category = $this->categoryRepository->get($categoryId); + /** + * The problem is that + * @see \Magento\Catalog\Controller\Adminhtml\Category\Save::execute + * saves the category via resource model, so the cache in the repository is not cleaned + */ + $newCategoryRepository = $this->_objectManager->create(CategoryRepositoryInterface::class); + $category = $newCategoryRepository->get($categoryId); $this->assertEquals($defaultUrlPath, $category->getData('url_key')); } From f4dc99152fe151d796ce37f06609501a2146b4df Mon Sep 17 00:00:00 2001 From: Stanislav Ilnytskyi Date: Mon, 4 Oct 2021 07:55:06 +0200 Subject: [PATCH 09/10] #22063 fix tests --- .../testsuite/Magento/Catalog/Model/CategoryTest.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/CategoryTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/CategoryTest.php index fb7f80bd72d56..fbe2c90be4952 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/CategoryTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/CategoryTest.php @@ -364,8 +364,13 @@ public function testDeleteChildren(): void */ public function testChildrenCountAfterDeleteParentCategory(): void { + $childrenCountInParent = $this->categoryResource->getChildrenCount(1); + $childrenCountInChild = $this->categoryResource->getChildrenCount(3); + $this->categoryRepository->deleteByIdentifier(3); - $this->assertEquals(8, $this->categoryResource->getChildrenCount(1)); + + $expectedCountAfterDelete = $childrenCountInParent - $childrenCountInChild - 1; + $this->assertEquals($expectedCountAfterDelete, $this->categoryResource->getChildrenCount(1)); } /** From 9c23fe6a82026f6157e5628d94f93d9abc03be18 Mon Sep 17 00:00:00 2001 From: Stanislav Ilnytskyi Date: Mon, 24 Apr 2023 19:46:08 +0200 Subject: [PATCH 10/10] static --- app/code/Magento/Catalog/Model/CategoryLinkRepository.php | 1 + app/code/Magento/Catalog/Model/CategoryRepository.php | 1 + .../Catalog/Test/Unit/Model/CategoryLinkRepositoryTest.php | 1 + 3 files changed, 3 insertions(+) diff --git a/app/code/Magento/Catalog/Model/CategoryLinkRepository.php b/app/code/Magento/Catalog/Model/CategoryLinkRepository.php index 0ca80acafa657..9eb9e3a55ad26 100644 --- a/app/code/Magento/Catalog/Model/CategoryLinkRepository.php +++ b/app/code/Magento/Catalog/Model/CategoryLinkRepository.php @@ -27,6 +27,7 @@ class CategoryLinkRepository implements CategoryLinkRepositoryInterface, Categor /** * @deprecated + * @see Product use faster resource model * @var ProductRepositoryInterface */ protected $productRepository; diff --git a/app/code/Magento/Catalog/Model/CategoryRepository.php b/app/code/Magento/Catalog/Model/CategoryRepository.php index 6c5319675ee6d..95e1232b976fa 100644 --- a/app/code/Magento/Catalog/Model/CategoryRepository.php +++ b/app/code/Magento/Catalog/Model/CategoryRepository.php @@ -231,6 +231,7 @@ protected function validateCategory(Category $category) * @return ExtensibleDataObjectConverter * * @deprecated 101.0.0 + * @see MAGETWO-71174 */ private function getExtensibleDataObjectConverter() { diff --git a/app/code/Magento/Catalog/Test/Unit/Model/CategoryLinkRepositoryTest.php b/app/code/Magento/Catalog/Test/Unit/Model/CategoryLinkRepositoryTest.php index 52c8631d10cf5..2dc0a734260a6 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/CategoryLinkRepositoryTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/CategoryLinkRepositoryTest.php @@ -37,6 +37,7 @@ class CategoryLinkRepositoryTest extends TestCase /** * @deprecated + * @see \Magento\Catalog\Model\CategoryLinkRepository * @var ProductRepositoryInterface|MockObject */ private $productRepositoryMock;