diff --git a/app/code/Magento/SalesSequence/Model/ResourceModel/Meta.php b/app/code/Magento/SalesSequence/Model/ResourceModel/Meta.php index 7a4aabea85680..8422123c0ca84 100644 --- a/app/code/Magento/SalesSequence/Model/ResourceModel/Meta.php +++ b/app/code/Magento/SalesSequence/Model/ResourceModel/Meta.php @@ -132,6 +132,7 @@ protected function _beforeSave(\Magento\Framework\Model\AbstractModel $object) || $object->getData('store_id') === null || !$object->getData('sequence_table') ) { + // phpcs:ignore Magento2.Exceptions.DirectThrow throw new Exception(__('Not enough arguments')); } diff --git a/app/code/Magento/SalesSequence/Model/Sequence/DeleteByStore.php b/app/code/Magento/SalesSequence/Model/Sequence/DeleteByStore.php new file mode 100644 index 0000000000000..e86cc8b1b2e6d --- /dev/null +++ b/app/code/Magento/SalesSequence/Model/Sequence/DeleteByStore.php @@ -0,0 +1,117 @@ +resourceMetadata = $resourceMetadata; + $this->metaFactory = $metaFactory; + $this->appResource = $appResource; + } + + /** + * Deletes all sequence linked entites + * + * @param int $storeId + * @return void + * @throws \Exception + */ + public function execute($storeId): void + { + $metadataIds = $this->getMetadataIdsByStoreId($storeId); + $profileIds = $this->getProfileIdsByMetadataIds($metadataIds); + + $this->appResource->getConnection()->delete( + $this->appResource->getTableName('sales_sequence_profile'), + ['profile_id IN (?)' => $profileIds] + ); + + foreach ($metadataIds as $metadataId) { + $metadata = $this->metaFactory->create(); + $this->resourceMetadata->load($metadata, $metadataId); + if (!$metadata->getId()) { + continue; + } + + $this->appResource->getConnection()->dropTable( + $metadata->getSequenceTable() + ); + $this->resourceMetadata->delete($metadata); + } + } + + /** + * Retrieves Metadata Ids by store id + * + * @param int $storeId + * @return int[] + */ + private function getMetadataIdsByStoreId($storeId) + { + $connection = $this->appResource->getConnection(); + $bind = ['store_id' => $storeId]; + $select = $connection->select()->from( + $this->appResource->getTableName('sales_sequence_meta'), + ['meta_id'] + )->where( + 'store_id = :store_id' + ); + + return $connection->fetchCol($select, $bind); + } + + /** + * Retrieves Profile Ids by metadata ids + * + * @param int[] $metadataIds + * @return int[] + */ + private function getProfileIdsByMetadataIds(array $metadataIds) + { + $connection = $this->appResource->getConnection(); + $select = $connection->select() + ->from( + $this->appResource->getTableName('sales_sequence_profile'), + ['profile_id'] + )->where('meta_id IN (?)', $metadataIds); + + return $connection->fetchCol($select); + } +} diff --git a/app/code/Magento/SalesSequence/Observer/SequenceRemovalObserver.php b/app/code/Magento/SalesSequence/Observer/SequenceRemovalObserver.php new file mode 100644 index 0000000000000..c10ef80f6eb9b --- /dev/null +++ b/app/code/Magento/SalesSequence/Observer/SequenceRemovalObserver.php @@ -0,0 +1,48 @@ +deleteByStore = $deleteByStore; + } + + /** + * Deletes all sequence linked entities. + * + * @param EventObserver $observer + * @return $this + * @throws \Magento\Framework\Exception\LocalizedException + */ + public function execute(EventObserver $observer) + { + if ($store = $observer->getData('store')) { + $this->deleteByStore->execute($store->getId()); + } + + return $this; + } +} diff --git a/app/code/Magento/SalesSequence/Test/Unit/Model/Sequence/DeleteByStoreTest.php b/app/code/Magento/SalesSequence/Test/Unit/Model/Sequence/DeleteByStoreTest.php new file mode 100644 index 0000000000000..17dbd6c37265f --- /dev/null +++ b/app/code/Magento/SalesSequence/Test/Unit/Model/Sequence/DeleteByStoreTest.php @@ -0,0 +1,147 @@ +connectionMock = $this->getMockForAbstractClass( + AdapterInterface::class, + [], + '', + false, + false, + true, + ['delete', 'query'] + ); + $this->resourceSequenceMeta = $this->createPartialMock( + ResourceMeta::class, + ['load', 'delete'] + ); + $this->meta = $this->createPartialMock( + Meta::class, + ['getSequenceTable'] + ); + $this->resourceMock = $this->createMock(ResourceConnection::class); + $this->select = $this->createMock(Select::class); + $this->metaFactory = $this->createPartialMock(MetaFactory::class, ['create']); + $this->metaFactory->method('create')->willReturn($this->meta); + + $helper = new ObjectManager($this); + $this->deleteByStore = $helper->getObject( + DeleteByStore::class, + [ + 'resourceMetadata' => $this->resourceSequenceMeta, + 'metaFactory' => $this->metaFactory, + 'appResource' => $this->resourceMock, + ] + ); + } + + /** + * @throws \Exception + * @SuppressWarnings(PHPMD.UnusedLocalVariable) + */ + public function testExecute() + { + $profileTableName = 'sales_sequence_profile'; + $storeId = 1; + $metadataIds = [1, 2]; + $profileIds = [10, 11]; + $this->resourceMock->method('getTableName') + ->willReturnCallback( + static function ($tableName) { + return $tableName; + } + ); + $this->resourceMock->method('getConnection') + ->willReturn($this->connectionMock); + $this->connectionMock + ->method('select') + ->willReturn($this->select); + + $this->select->method('from') + ->willReturn($this->select); + $this->select->method('where') + ->willReturn($this->select); + + $this->connectionMock->method('fetchCol') + ->willReturnCallback( + static function ($arg, $arg2) use ($metadataIds, $profileIds) { + if (array_key_exists('store', $arg2)) { + return $metadataIds; + } + + return $profileIds; + } + ); + + $this->connectionMock->expects($this->once()) + ->method('delete') + ->with($profileTableName, ['profile_id IN (?)' => $profileIds]) + ->willReturn(2); + $this->resourceSequenceMeta + ->method('load') + ->willReturn($this->meta); + $this->connectionMock + ->method('dropTable') + ->willReturn(true); + $this->resourceSequenceMeta + ->method('delete') + ->willReturn($this->resourceSequenceMeta); + $this->deleteByStore->execute($storeId); + } +} diff --git a/app/code/Magento/SalesSequence/etc/events.xml b/app/code/Magento/SalesSequence/etc/events.xml new file mode 100644 index 0000000000000..5bbde6ab188a5 --- /dev/null +++ b/app/code/Magento/SalesSequence/etc/events.xml @@ -0,0 +1,12 @@ + + + + + + + diff --git a/dev/tests/integration/framework/Magento/TestFramework/Application.php b/dev/tests/integration/framework/Magento/TestFramework/Application.php index 1bfc928f2916a..f0ce2e24545eb 100644 --- a/dev/tests/integration/framework/Magento/TestFramework/Application.php +++ b/dev/tests/integration/framework/Magento/TestFramework/Application.php @@ -558,7 +558,7 @@ private function copyAppConfigFiles() } } } - + /** * Copies global configuration file from the tests folder (see TESTS_GLOBAL_CONFIG_FILE) * diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/UrlTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/UrlTest.php index ff2979150954e..451e19be28e5f 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/UrlTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/UrlTest.php @@ -53,8 +53,8 @@ public function testGetUrlInStore() * @magentoConfigFixture fixturestore_store web/unsecure/base_url http://sample-second.com/ * @magentoConfigFixture fixturestore_store web/unsecure/base_link_url http://sample-second.com/ * @magentoDataFixture Magento/Catalog/_files/product_simple_multistore.php - * @magentoDbIsolation disabled * @dataProvider getUrlsWithSecondStoreProvider + * @magentoDbIsolation disabled * @magentoAppArea adminhtml */ public function testGetUrlInStoreWithSecondStore($storeCode, $expectedProductUrl) diff --git a/dev/tests/integration/testsuite/Magento/Store/Model/StoreTest.php b/dev/tests/integration/testsuite/Magento/Store/Model/StoreTest.php index 00de5544d8fb7..58c7d1cba45fe 100644 --- a/dev/tests/integration/testsuite/Magento/Store/Model/StoreTest.php +++ b/dev/tests/integration/testsuite/Magento/Store/Model/StoreTest.php @@ -176,11 +176,13 @@ public function getBaseUrlDataProvider() */ public function testGetBaseUrlInPub() { - \Magento\TestFramework\Helper\Bootstrap::getInstance()->reinitialize([ - Bootstrap::INIT_PARAM_FILESYSTEM_DIR_PATHS => [ - DirectoryList::PUB => [DirectoryList::URL_PATH => ''], - ], - ]); + \Magento\TestFramework\Helper\Bootstrap::getInstance()->reinitialize( + [ + Bootstrap::INIT_PARAM_FILESYSTEM_DIR_PATHS => [ + DirectoryList::PUB => [DirectoryList::URL_PATH => ''], + ], + ] + ); $this->model = $this->_getStoreModel(); $this->model->load('default'); @@ -276,14 +278,14 @@ public function testIsCanDelete() /** * @magentoDataFixture Magento/Store/_files/core_second_third_fixturestore.php - * @magentoDataFixture Magento/Catalog/_files/product_simple.php - * @magentoDbIsolation disabled + * @magentoDataFixture Magento/Catalog/_files/products.php + * @magentoAppIsolation enabled */ public function testGetCurrentUrl() { $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); $objectManager->get(\Magento\Framework\App\Config\MutableScopeConfigInterface::class) - ->setValue('web/url/use_store', true, ScopeInterface::SCOPE_STORE, 'secondstore'); + ->setValue('web/url/use_store', true, ScopeInterface::SCOPE_STORE, 'secondstore'); $this->model->load('admin'); $this->model @@ -316,9 +318,10 @@ public function testGetCurrentUrl() } /** - * @magentoDataFixture Magento/Store/_files/second_store.php - * @magentoDataFixture Magento/Catalog/_files/category_product.php - * @magentoDbIsolation disabled + * @magentoDataFixture Magento/Store/_files/core_second_third_fixturestore.php + * @magentoDataFixture Magento/Catalog/_files/products.php + * @magentoAppIsolation enabled + * @magentoDbIsolation enabled */ public function testGetCurrentUrlWithUseStoreInUrlFalse() { @@ -327,34 +330,34 @@ public function testGetCurrentUrlWithUseStoreInUrlFalse() ->setValue('web/url/use_store', false, ScopeInterface::SCOPE_STORE, 'default'); /** @var \Magento\Store\Model\Store $secondStore */ - $secondStore = $objectManager->get(StoreRepositoryInterface::class)->get('fixture_second_store'); + $secondStore = $objectManager->get(StoreRepositoryInterface::class)->get('secondstore'); /** @var \Magento\Catalog\Model\ProductRepository $productRepository */ $productRepository = $objectManager->create(ProductRepository::class); - $product = $productRepository->get('simple333'); + $product = $productRepository->get('simple'); $product->setStoreId($secondStore->getId()); $url = $product->getUrlInStore(); /** @var \Magento\Catalog\Model\CategoryRepository $categoryRepository */ $categoryRepository = $objectManager->get(\Magento\Catalog\Model\CategoryRepository::class); - $category = $categoryRepository->get(333, $secondStore->getStoreId()); + $category = $categoryRepository->get(2, $secondStore->getStoreId()); $this->assertEquals( - $secondStore->getBaseUrl() . 'catalog/category/view/s/category-1/id/333/', + $secondStore->getBaseUrl() . 'catalog/category/view/s/default-category/id/2/', $category->getUrl() ); $this->assertEquals( $secondStore->getBaseUrl() . - 'catalog/product/view/id/333/s/simple-product-three/?___store=fixture_second_store', + 'catalog/product/view/id/1/s/simple-product/?___store=secondstore', $url ); $this->assertEquals( - $secondStore->getBaseUrl() . '?___store=fixture_second_store&___from_store=default', + $secondStore->getBaseUrl() . '?___store=secondstore&___from_store=default', $secondStore->getCurrentUrl() ); $this->assertEquals( - $secondStore->getBaseUrl() . '?___store=fixture_second_store', + $secondStore->getBaseUrl() . '?___store=secondstore', $secondStore->getCurrentUrl(false) ); } @@ -366,14 +369,16 @@ public function testGetCurrentUrlWithUseStoreInUrlFalse() */ public function testCRUD() { - $this->model->setData([ - 'code' => 'test', - 'website_id' => 1, - 'group_id' => 1, - 'name' => 'test name', - 'sort_order' => 0, - 'is_active' => 1, - ]); + $this->model->setData( + [ + 'code' => 'test', + 'website_id' => 1, + 'group_id' => 1, + 'name' => 'test name', + 'sort_order' => 0, + 'is_active' => 1, + ] + ); $crud = new \Magento\TestFramework\Entity( $this->model, ['name' => 'new name'], @@ -446,8 +451,8 @@ public function testIsUseStoreInUrl($storeInUrl, $disableStoreInUrl, $expectedRe } /** - * @see self::testIsUseStoreInUrl; * @return array + * @see self::testIsUseStoreInUrl; */ public function isUseStoreInUrlDataProvider() {