diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Duplicate.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Duplicate.php index 90b8ee3164183..6a5c69a83331d 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Duplicate.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Duplicate.php @@ -5,57 +5,68 @@ */ namespace Magento\Catalog\Controller\Adminhtml\Product; -use Magento\Backend\App\Action; +use Magento\Backend\App\Action\Context; +use Magento\Backend\Model\View\Result\Redirect; use Magento\Catalog\Controller\Adminhtml\Product; +use Magento\Catalog\Model\Product\Copier; +use Magento\Catalog\Model\ProductFactory; +use Magento\Framework\App\Action\HttpGetActionInterface; use Magento\Framework\App\ObjectManager; +use Psr\Log\LoggerInterface; /** - * Class Duplicate + * Class Duplicate product */ -class Duplicate extends \Magento\Catalog\Controller\Adminhtml\Product implements - \Magento\Framework\App\Action\HttpGetActionInterface +class Duplicate extends Product implements HttpGetActionInterface { /** - * @var \Magento\Catalog\Model\Product\Copier + * @var Copier */ protected $productCopier; /** - * @var \Psr\Log\LoggerInterface + * @var LoggerInterface */ private $logger; /** - * @param Action\Context $context + * @var ProductFactory + */ + private $productFactory; + + /** + * @param Context $context * @param Builder $productBuilder - * @param \Magento\Catalog\Model\Product\Copier $productCopier - * @param \Psr\Log\LoggerInterface $logger + * @param Copier $productCopier + * @param LoggerInterface|null $logger + * @param ProductFactory|null $productFactory */ public function __construct( - \Magento\Backend\App\Action\Context $context, + Context $context, Product\Builder $productBuilder, - \Magento\Catalog\Model\Product\Copier $productCopier, - \Psr\Log\LoggerInterface $logger = null + Copier $productCopier, + LoggerInterface $logger = null, + ?ProductFactory $productFactory = null ) { $this->productCopier = $productCopier; - $this->logger = $logger ?: ObjectManager::getInstance() - ->get(\Psr\Log\LoggerInterface::class); + $this->logger = $logger ?: ObjectManager::getInstance()->get(LoggerInterface::class); + $this->productFactory = $productFactory ?: ObjectManager::getInstance()->get(ProductFactory::class); parent::__construct($context, $productBuilder); } /** * Create product duplicate * - * @return \Magento\Backend\Model\View\Result\Redirect + * @return Redirect */ public function execute() { - /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ + /** @var Redirect $resultRedirect */ $resultRedirect = $this->resultRedirectFactory->create(); $product = $this->productBuilder->build($this->getRequest()); try { - $newProduct = $this->productCopier->copy($product); + $newProduct = $this->productCopier->copy($product, $this->productFactory->create()); $this->messageManager->addSuccessMessage(__('You duplicated the product.')); $resultRedirect->setPath('catalog/*/edit', ['_current' => true, 'id' => $newProduct->getId()]); } catch (\Exception $e) { diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Save.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Save.php index 97b57317851fc..ca2d80bcc99ce 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Save.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Save.php @@ -6,20 +6,28 @@ namespace Magento\Catalog\Controller\Adminhtml\Product; -use Magento\Framework\App\Action\HttpPostActionInterface as HttpPostActionInterface; -use Magento\Backend\App\Action; +use Magento\Backend\App\Action\Context; +use Magento\Backend\Model\View\Result\Redirect; +use Magento\Catalog\Api\CategoryLinkManagementInterface; use Magento\Catalog\Api\Data\ProductInterface; +use Magento\Catalog\Api\ProductRepositoryInterface; use Magento\Catalog\Controller\Adminhtml\Product; +use Magento\Catalog\Model\Product\Copier; +use Magento\Catalog\Model\Product\TypeTransitionManager; +use Magento\Catalog\Model\ProductFactory; +use Magento\Framework\App\Action\HttpPostActionInterface as HttpPostActionInterface; use Magento\Framework\App\ObjectManager; -use Magento\Store\Model\StoreManagerInterface; use Magento\Framework\App\Request\DataPersistorInterface; +use Magento\Framework\Escaper; +use Magento\Store\Model\StoreManagerInterface; +use Psr\Log\LoggerInterface; /** * Product save controller * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ -class Save extends \Magento\Catalog\Controller\Adminhtml\Product implements HttpPostActionInterface +class Save extends Product implements HttpPostActionInterface { /** * @var Initialization\Helper @@ -27,22 +35,22 @@ class Save extends \Magento\Catalog\Controller\Adminhtml\Product implements Http protected $initializationHelper; /** - * @var \Magento\Catalog\Model\Product\Copier + * @var Copier */ protected $productCopier; /** - * @var \Magento\Catalog\Model\Product\TypeTransitionManager + * @var TypeTransitionManager */ protected $productTypeManager; /** - * @var \Magento\Catalog\Api\CategoryLinkManagementInterface + * @var CategoryLinkManagementInterface */ protected $categoryLinkManagement; /** - * @var \Magento\Catalog\Api\ProductRepositoryInterface + * @var ProductRepositoryInterface */ protected $productRepository; @@ -57,61 +65,66 @@ class Save extends \Magento\Catalog\Controller\Adminhtml\Product implements Http private $storeManager; /** - * @var \Magento\Framework\Escaper + * @var Escaper */ private $escaper; /** - * @var \Psr\Log\LoggerInterface + * @var LoggerInterface */ private $logger; + /** + * @var ProductFactory + */ + private $productFactory; + /** * Save constructor. * - * @param Action\Context $context + * @param Context $context * @param Builder $productBuilder * @param Initialization\Helper $initializationHelper - * @param \Magento\Catalog\Model\Product\Copier $productCopier - * @param \Magento\Catalog\Model\Product\TypeTransitionManager $productTypeManager - * @param \Magento\Catalog\Api\ProductRepositoryInterface $productRepository - * @param \Magento\Framework\Escaper $escaper - * @param \Psr\Log\LoggerInterface $logger - * @param \Magento\Catalog\Api\CategoryLinkManagementInterface $categoryLinkManagement - * @param StoreManagerInterface $storeManager + * @param Copier $productCopier + * @param TypeTransitionManager $productTypeManager + * @param ProductRepositoryInterface $productRepository + * @param Escaper|null $escaper + * @param LoggerInterface|null $logger + * @param CategoryLinkManagementInterface|null $categoryLinkManagement + * @param StoreManagerInterface|null $storeManager + * @param ProductFactory|null $productFactory * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( - \Magento\Backend\App\Action\Context $context, + Context $context, Product\Builder $productBuilder, Initialization\Helper $initializationHelper, - \Magento\Catalog\Model\Product\Copier $productCopier, - \Magento\Catalog\Model\Product\TypeTransitionManager $productTypeManager, - \Magento\Catalog\Api\ProductRepositoryInterface $productRepository, - \Magento\Framework\Escaper $escaper = null, - \Psr\Log\LoggerInterface $logger = null, - \Magento\Catalog\Api\CategoryLinkManagementInterface $categoryLinkManagement = null, - \Magento\Store\Model\StoreManagerInterface $storeManager = null + Copier $productCopier, + TypeTransitionManager $productTypeManager, + ProductRepositoryInterface $productRepository, + Escaper $escaper = null, + LoggerInterface $logger = null, + CategoryLinkManagementInterface $categoryLinkManagement = null, + StoreManagerInterface $storeManager = null, + ?ProductFactory $productFactory = null ) { parent::__construct($context, $productBuilder); $this->initializationHelper = $initializationHelper; $this->productCopier = $productCopier; $this->productTypeManager = $productTypeManager; $this->productRepository = $productRepository; - $this->escaper = $escaper ?: ObjectManager::getInstance() - ->get(\Magento\Framework\Escaper::class); - $this->logger = $logger ?: ObjectManager::getInstance() - ->get(\Psr\Log\LoggerInterface::class); + $this->escaper = $escaper ?: ObjectManager::getInstance()->get(Escaper::class); + $this->logger = $logger ?: ObjectManager::getInstance()->get(LoggerInterface::class); $this->categoryLinkManagement = $categoryLinkManagement ?: ObjectManager::getInstance() - ->get(\Magento\Catalog\Api\CategoryLinkManagementInterface::class); - $this->storeManager = $storeManager ?: ObjectManager::getInstance() - ->get(\Magento\Store\Model\StoreManagerInterface::class); + ->get(CategoryLinkManagementInterface::class); + $this->storeManager = $storeManager ?: ObjectManager::getInstance()->get(StoreManagerInterface::class); + $this->productFactory = $productFactory ?: ObjectManager::getInstance()->get(ProductFactory::class); } /** * Save product action * - * @return \Magento\Backend\Model\View\Result\Redirect + * @return Redirect * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.NPathComplexity) */ @@ -166,7 +179,7 @@ public function execute() if ($redirectBack === 'duplicate') { $product->unsetData('quantity_and_stock_status'); - $newProduct = $this->productCopier->copy($product); + $newProduct = $this->productCopier->copy($product, $this->productFactory->create()); $this->checkUniqueAttributes($product); $this->messageManager->addSuccessMessage(__('You duplicated the product.')); } diff --git a/app/code/Magento/Catalog/Model/Product/Copier.php b/app/code/Magento/Catalog/Model/Product/Copier.php index b04d3da8f0223..6959813b3e6d3 100644 --- a/app/code/Magento/Catalog/Model/Product/Copier.php +++ b/app/code/Magento/Catalog/Model/Product/Copier.php @@ -11,10 +11,8 @@ use Magento\Catalog\Model\Product\Attribute\Source\Status; use Magento\Catalog\Model\Product\Option\Repository as OptionRepository; use Magento\Catalog\Model\ProductFactory; -use Magento\Framework\App\ObjectManager; use Magento\Framework\EntityManager\MetadataPool; use Magento\Store\Model\Store; -use Magento\UrlRewrite\Model\Exception\UrlAlreadyExistsException; /** * Catalog product copier. @@ -75,20 +73,19 @@ public function __construct( * Create product duplicate * * @param Product $product + * @param Product $duplicate * @return Product */ - public function copy(Product $product): Product + public function copy(Product $product, Product $duplicate): Product { $product->getWebsiteIds(); $product->getCategoryIds(); $metadata = $this->metadataPool->getMetadata(ProductInterface::class); - /** @var Product $duplicate */ - $duplicate = $this->productFactory->create(); $productData = $product->getData(); $productData = $this->removeStockItem($productData); - $duplicate->setData($productData); + $duplicate->addData($productData); $duplicate->setOptions([]); $duplicate->setMetaTitle(null); $duplicate->setMetaKeyword(null); @@ -101,95 +98,12 @@ public function copy(Product $product): Product $duplicate->setId(null); $duplicate->setStoreId(Store::DEFAULT_STORE_ID); $this->copyConstructor->build($product, $duplicate); - $this->setDefaultUrl($product, $duplicate); - $this->setStoresUrl($product, $duplicate); + $duplicate->save(); $this->optionRepository->duplicate($product, $duplicate); return $duplicate; } - /** - * Set default URL. - * - * @param Product $product - * @param Product $duplicate - * @return void - */ - private function setDefaultUrl(Product $product, Product $duplicate) : void - { - $duplicate->setStoreId(Store::DEFAULT_STORE_ID); - $resource = $product->getResource(); - $attribute = $resource->getAttribute('url_key'); - $productId = $product->getId(); - $urlKey = $resource->getAttributeRawValue($productId, 'url_key', Store::DEFAULT_STORE_ID); - do { - $urlKey = $this->modifyUrl($urlKey); - $duplicate->setUrlKey($urlKey); - } while (!$attribute->getEntity()->checkAttributeUniqueValue($attribute, $duplicate)); - $duplicate->setData('url_path', null); - $duplicate->save(); - } - - /** - * Set URL for each store. - * - * @param Product $product - * @param Product $duplicate - * - * @return void - * @throws UrlAlreadyExistsException - */ - private function setStoresUrl(Product $product, Product $duplicate) : void - { - $storeIds = $duplicate->getStoreIds(); - $productId = $product->getId(); - $productResource = $product->getResource(); - $attribute = $productResource->getAttribute('url_key'); - $duplicate->setData('save_rewrites_history', false); - foreach ($storeIds as $storeId) { - $useDefault = !$this->scopeOverriddenValue->containsValue( - ProductInterface::class, - $product, - 'url_key', - $storeId - ); - if ($useDefault) { - continue; - } - - $duplicate->setStoreId($storeId); - $urlKey = $productResource->getAttributeRawValue($productId, 'url_key', $storeId); - $iteration = 0; - - do { - if ($iteration === 10) { - throw new UrlAlreadyExistsException(); - } - - $urlKey = $this->modifyUrl($urlKey); - $duplicate->setUrlKey($urlKey); - $iteration++; - } while (!$attribute->getEntity()->checkAttributeUniqueValue($attribute, $duplicate)); - $duplicate->setData('url_path', null); - $productResource->saveAttribute($duplicate, 'url_path'); - $productResource->saveAttribute($duplicate, 'url_key'); - } - $duplicate->setStoreId(Store::DEFAULT_STORE_ID); - } - - /** - * Modify URL key. - * - * @param string $urlKey - * @return string - */ - private function modifyUrl(string $urlKey) : string - { - return preg_match('/(.*)-(\d+)$/', $urlKey, $matches) - ? $matches[1] . '-' . ($matches[2] + 1) - : $urlKey . '-1'; - } - /** * Remove stock item * @@ -204,6 +118,7 @@ private function removeStockItem(array $productData): array $extensionAttributes->setData('stock_item', null); } } + return $productData; } } diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Product/CopierTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Product/CopierTest.php index d3a4494c071b7..6574a9701777d 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Product/CopierTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Product/CopierTest.php @@ -20,9 +20,12 @@ use Magento\CatalogInventory\Api\Data\StockItemInterface; use Magento\Eav\Model\Entity\AbstractEntity; use Magento\Eav\Model\Entity\Attribute\AbstractAttribute; +use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Framework\EntityManager\EntityMetadata; use Magento\Framework\EntityManager\MetadataPool; use Magento\UrlRewrite\Model\Exception\UrlAlreadyExistsException; +use Magento\UrlRewrite\Model\ResourceModel\UrlRewriteCollectionFactory; +use Magento\UrlRewrite\Model\ResourceModel\UrlRewriteCollection; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -68,6 +71,16 @@ class CopierTest extends TestCase */ private $metadata; + /** + * @var ScopeConfigInterface|MockObject + */ + private $scopeConfigMock; + + /** + * @var UrlRewriteCollection|MockObject + */ + private $urlRewriteCollectionMock; + /** * @ingeritdoc */ @@ -78,6 +91,14 @@ protected function setUp(): void $this->scopeOverriddenValueMock = $this->createMock(ScopeOverriddenValue::class); $this->optionRepositoryMock = $this->createMock(Repository::class); $this->productMock = $this->createMock(Product::class); + $this->scopeConfigMock = $this->createMock(ScopeConfigInterface::class); + + $this->urlRewriteCollectionMock = $this->createMock(UrlRewriteCollection::class); + $this->urlRewriteCollectionMock->method('addFieldToFilter') + ->willReturnSelf(); + $urlRewriteCollectionFactoryMock = $this->createMock(UrlRewriteCollectionFactory::class); + $urlRewriteCollectionFactoryMock->method('create') + ->willReturn($this->urlRewriteCollectionMock); $this->metadata = $this->getMockBuilder(EntityMetadata::class) ->disableOriginalConstructor() @@ -95,7 +116,9 @@ protected function setUp(): void $this->productFactoryMock, $this->scopeOverriddenValueMock, $this->optionRepositoryMock, - $metadataPool + $metadataPool, + $this->scopeConfigMock, + $urlRewriteCollectionFactoryMock ); } @@ -144,37 +167,6 @@ public function testCopy(): void true, ['checkAttributeUniqueValue'] ); - $entityMock->expects($this->once()) - ->method('checkAttributeUniqueValue') - ->willReturn(true); - - $attributeMock = $this->getMockForAbstractClass( - AbstractAttribute::class, - [], - '', - false, - true, - true, - ['getEntity'] - ); - $attributeMock->expects($this->once()) - ->method('getEntity') - ->willReturn($entityMock); - - $resourceMock = $this->getMockBuilder(ProductResourceModel::class) - ->disableOriginalConstructor() - ->setMethods(['getAttributeRawValue', 'duplicate', 'getAttribute']) - ->getMock(); - $resourceMock->expects($this->once()) - ->method('getAttributeRawValue') - ->willReturn('urk-key-1'); - $resourceMock->expects($this->exactly(2)) - ->method('getAttribute') - ->willReturn($attributeMock); - - $this->productMock->expects($this->exactly(2)) - ->method('getResource') - ->willReturn($resourceMock); $duplicateMock = $this->getMockBuilder(Product::class) ->addMethods( @@ -204,9 +196,6 @@ public function testCopy(): void ) ->disableOriginalConstructor() ->getMock(); - $this->productFactoryMock->expects($this->once()) - ->method('create') - ->willReturn($duplicateMock); $duplicateMock->expects($this->once())->method('setOptions')->with([]); $duplicateMock->expects($this->once())->method('setIsDuplicate')->with(true); @@ -233,18 +222,14 @@ public function testCopy(): void $duplicateMock->expects($this->once()) ->method('setMetaDescription') ->with(null); - $duplicateMock->expects($this->atLeastOnce()) - ->method('getStoreIds')->willReturn([]); + $duplicateMock->expects($this->atLeastOnce()) ->method('setData') ->willReturn($duplicateMock); $this->copyConstructorMock->expects($this->once()) ->method('build') ->with($this->productMock, $duplicateMock); - $duplicateMock->expects($this->once()) - ->method('setUrlKey') - ->with('urk-key-2') - ->willReturn($duplicateMock); + $duplicateMock->expects($this->once()) ->method('save'); $this->metadata->expects($this->once()) @@ -256,7 +241,7 @@ public function testCopy(): void ->method('duplicate') ->with($this->productMock, $duplicateMock); - $this->assertEquals($duplicateMock, $this->_model->copy($this->productMock)); + $this->assertEquals($duplicateMock, $this->_model->copy($this->productMock, $duplicateMock)); } /** @@ -301,9 +286,6 @@ public function testUrlAlreadyExistsExceptionWhileCopyStoresUrl(): void true, ['checkAttributeUniqueValue'] ); - $entityMock->expects($this->exactly(11)) - ->method('checkAttributeUniqueValue') - ->willReturn(true, false); $attributeMock = $this->getMockForAbstractClass( AbstractAttribute::class, @@ -322,9 +304,6 @@ public function testUrlAlreadyExistsExceptionWhileCopyStoresUrl(): void ->disableOriginalConstructor() ->setMethods(['getAttributeRawValue', 'duplicate', 'getAttribute']) ->getMock(); - $resourceMock->expects($this->any()) - ->method('getAttributeRawValue') - ->willReturn('urk-key-1'); $resourceMock->expects($this->any()) ->method('getAttribute') ->willReturn($attributeMock); @@ -350,7 +329,6 @@ public function testUrlAlreadyExistsExceptionWhileCopyStoresUrl(): void ) ->disableOriginalConstructor() ->getMock(); - $this->productFactoryMock->expects($this->once())->method('create')->willReturn($duplicateMock); $duplicateMock->expects($this->once())->method('setOptions')->with([]); $duplicateMock->expects($this->once())->method('setIsDuplicate')->with(true); @@ -366,21 +344,10 @@ public function testUrlAlreadyExistsExceptionWhileCopyStoresUrl(): void $duplicateMock->expects($this->once())->method('setCreatedAt')->with(null); $duplicateMock->expects($this->once())->method('setUpdatedAt')->with(null); $duplicateMock->expects($this->once())->method('setId')->with(null); - $duplicateMock->expects($this->atLeastOnce())->method('getStoreIds')->willReturn([1]); $duplicateMock->expects($this->atLeastOnce())->method('setData')->willReturn($duplicateMock); $this->copyConstructorMock->expects($this->once())->method('build')->with($this->productMock, $duplicateMock); - $duplicateMock->expects( - $this->exactly(11) - )->method( - 'setUrlKey' - )->with( - $this->stringContains('urk-key-') - )->willReturn( - $duplicateMock - ); - $duplicateMock->expects($this->once())->method('save'); - $this->scopeOverriddenValueMock->expects($this->once())->method('containsValue')->willReturn(true); + $duplicateMock->expects($this->once())->method('save'); $this->metadata->expects($this->any())->method('getLinkField')->willReturn('linkField'); @@ -388,7 +355,6 @@ public function testUrlAlreadyExistsExceptionWhileCopyStoresUrl(): void ['linkField', null, '2'], ]); - $this->expectException(UrlAlreadyExistsException::class); - $this->_model->copy($this->productMock); + $this->_model->copy($this->productMock, $duplicateMock); } } diff --git a/app/code/Magento/CatalogUrlRewrite/Plugin/Catalog/Model/Product/SetUrlsToCopiedProduct.php b/app/code/Magento/CatalogUrlRewrite/Plugin/Catalog/Model/Product/SetUrlsToCopiedProduct.php new file mode 100644 index 0000000000000..8ea3fee9f6c56 --- /dev/null +++ b/app/code/Magento/CatalogUrlRewrite/Plugin/Catalog/Model/Product/SetUrlsToCopiedProduct.php @@ -0,0 +1,220 @@ +productResource = $productResource; + $this->scopeOverriddenValue = $scopeOverriddenValue; + $this->scopeConfig = $scopeConfig; + $this->urlRewriteCollectionFactory = $urlRewriteCollectionFactory; + $this->optionRepository = $optionRepository; + } + + /** + * Sets default url to duplicated product + * + * @param Copier $subject + * @param Product $duplicate + * @param Product $product + * @return array + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function beforeCopy(Copier $subject, Product $product, Product $duplicate): array + { + $this->setDefaultUrl($product, $duplicate); + $product->unsetData('url_key'); + + return [$product, $duplicate]; + } + + /** + * Sets stores urls to duplicated product + * + * @param Copier $subject + * @param Product $duplicate + * @param Product $product + * @return Product + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function afterCopy(Copier $subject, Product $duplicate, Product $product): Product + { + $this->setStoresUrl($product, $duplicate); + + return $duplicate; + } + + /** + * Set default URL. + * + * @param Product $product + * @param Product $duplicate + * @return void + */ + private function setDefaultUrl(Product $product, Product $duplicate): void + { + $duplicate->setStoreId(Store::DEFAULT_STORE_ID); + $productId = $product->getId(); + $urlKey = $this->productResource->getAttributeRawValue( + $productId, + self::URL_KEY_ATTRIBUTE, + Store::DEFAULT_STORE_ID + ); + do { + $urlKey = $this->modifyUrl($urlKey); + $duplicate->setUrlKey($urlKey); + } while ($this->isUrlRewriteExists($urlKey)); + $duplicate->setData(self::URL_PATH_ATTRIBUTE, null); + } + + /** + * Set URL for each store. + * + * @param Product $product + * @param Product $duplicate + * @return void + * @throws UrlAlreadyExistsException + * @throws LocalizedException + */ + private function setStoresUrl(Product $product, Product $duplicate): void + { + $productId = $product->getId(); + $attribute = $this->productResource->getAttribute(self::URL_KEY_ATTRIBUTE); + $duplicate->setData('save_rewrites_history', false); + foreach ($duplicate->getStoreIds() as $storeId) { + $useDefault = !$this->scopeOverriddenValue->containsValue( + ProductInterface::class, + $product, + self::URL_KEY_ATTRIBUTE, + $storeId + ); + if ($useDefault) { + continue; + } + + $duplicate->setStoreId($storeId); + $urlKey = $this->productResource->getAttributeRawValue($productId, self::URL_KEY_ATTRIBUTE, $storeId); + $iteration = 0; + + do { + if ($iteration === 10) { + throw new UrlAlreadyExistsException(); + } + + $urlKey = $this->modifyUrl($urlKey); + $duplicate->setUrlKey($urlKey); + $iteration++; + } while (!$attribute->getEntity()->checkAttributeUniqueValue($attribute, $duplicate)); + $duplicate->setData(self::URL_PATH_ATTRIBUTE, null); + $this->productResource->saveAttribute($duplicate, self::URL_PATH_ATTRIBUTE); + $this->productResource->saveAttribute($duplicate, self::URL_KEY_ATTRIBUTE); + } + } + + /** + * Modify URL key. + * + * @param string $urlKey + * @return string + */ + private function modifyUrl(string $urlKey): string + { + return preg_match(self::URL_PATTERN, $urlKey, $matches) + ? $matches[1] . '-' . ($matches[2] + 1) + : $urlKey . '-1'; + } + + /** + * Verify if generated url rewrite exists in url_rewrite table + * + * @param string $urlKey + * @return bool + */ + private function isUrlRewriteExists(string $urlKey): bool + { + $urlRewriteCollection = $this->urlRewriteCollectionFactory->create(); + $urlRewriteCollection->addFieldToFilter(UrlRewrite::ENTITY_TYPE, self::ENTITY_TYPE) + ->addFieldToFilter(UrlRewrite::REQUEST_PATH, $urlKey . $this->getUrlSuffix()); + + return $urlRewriteCollection->getSize() !== 0; + } + + /** + * Returns default product url suffix config + * + * @return string|null + */ + private function getUrlSuffix(): ?string + { + return $this->scopeConfig->getValue(ProductUrlPathGenerator::XML_PATH_PRODUCT_URL_SUFFIX); + } +} diff --git a/app/code/Magento/CatalogUrlRewrite/etc/di.xml b/app/code/Magento/CatalogUrlRewrite/etc/di.xml index 5c25d11986eb9..0b3de5035d76f 100644 --- a/app/code/Magento/CatalogUrlRewrite/etc/di.xml +++ b/app/code/Magento/CatalogUrlRewrite/etc/di.xml @@ -70,4 +70,8 @@ + + + diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Backend/SkuTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Backend/SkuTest.php index f557919897869..e70d57042d562 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Backend/SkuTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Backend/SkuTest.php @@ -3,22 +3,32 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Catalog\Model\Product\Attribute\Backend; +use Magento\Catalog\Model\Product; +use Magento\Catalog\Model\Product\Attribute\Source\Status; +use Magento\Catalog\Model\Product\Copier; +use Magento\Catalog\Model\Product\Type; +use Magento\Catalog\Model\Product\Visibility; +use Magento\Catalog\Model\ProductFactory; +use Magento\Catalog\Model\ProductRepository; +use Magento\TestFramework\Helper\Bootstrap; +use PHPUnit\Framework\TestCase; + /** * Test class for \Magento\Catalog\Model\Product\Attribute\Backend\Sku. * @magentoAppArea adminhtml */ -class SkuTest extends \PHPUnit\Framework\TestCase +class SkuTest extends TestCase { /** * @magentoDataFixture Magento/Catalog/_files/product_simple.php */ - public function testGenerateUniqueSkuExistingProduct() + public function testGenerateUniqueSkuExistingProduct(): void { - $repository = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( - \Magento\Catalog\Model\ProductRepository::class - ); + $repository = Bootstrap::getObjectManager()->create(ProductRepository::class); $product = $repository->get('simple'); $product->setId(null); $this->assertEquals('simple', $product->getSku()); @@ -27,10 +37,10 @@ public function testGenerateUniqueSkuExistingProduct() } /** - * @param $product \Magento\Catalog\Model\Product + * @param $product Product * @dataProvider uniqueSkuDataProvider */ - public function testGenerateUniqueSkuNotExistingProduct($product) + public function testGenerateUniqueSkuNotExistingProduct(Product $product): void { $this->assertEquals('simple', $product->getSku()); $product->getResource()->getAttribute('sku')->getBackend()->beforeSave($product); @@ -42,19 +52,16 @@ public function testGenerateUniqueSkuNotExistingProduct($product) * @magentoAppArea adminhtml * @magentoDbIsolation enabled */ - public function testGenerateUniqueLongSku() + public function testGenerateUniqueLongSku(): void { - $repository = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( - \Magento\Catalog\Model\ProductRepository::class - ); + $repository = Bootstrap::getObjectManager()->create(ProductRepository::class); + $productFactory = Bootstrap::getObjectManager()->create(ProductFactory::class); $product = $repository->get('simple'); $product->setSku('0123456789012345678901234567890123456789012345678901234567890123'); - /** @var \Magento\Catalog\Model\Product\Copier $copier */ - $copier = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( - \Magento\Catalog\Model\Product\Copier::class - ); - $copier->copy($product); + /** @var Copier $copier */ + $copier = Bootstrap::getObjectManager()->get(Copier::class); + $copier->copy($product, $productFactory->create()); $this->assertEquals('0123456789012345678901234567890123456789012345678901234567890123', $product->getSku()); $product->getResource()->getAttribute('sku')->getBackend()->beforeSave($product); $this->assertEquals('01234567890123456789012345678901234567890123456789012345678901-1', $product->getSku()); @@ -65,48 +72,34 @@ public function testGenerateUniqueLongSku() * * @return array */ - public function uniqueSkuDataProvider() + public function uniqueSkuDataProvider(): array { - $product = $this->_getProduct(); + $product = $this->getProduct(); return [[$product]]; } /** * Get product form data provider * - * @return \Magento\Catalog\Model\Product + * @return Product */ - protected function _getProduct() + private function getProduct(): Product { - /** @var $product \Magento\Catalog\Model\Product */ - $product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( - \Magento\Catalog\Model\Product::class - ); - $product->setTypeId( - \Magento\Catalog\Model\Product\Type::TYPE_SIMPLE - )->setId( - 1 - )->setAttributeSetId( - 4 - )->setWebsiteIds( - [1] - )->setName( - 'Simple Product' - )->setSku( - 'simple' - )->setPrice( - 10 - )->setDescription( - 'Description with html tag' - )->setVisibility( - \Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH - )->setStatus( - \Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED - )->setCategoryIds( - [2] - )->setStockData( - ['use_config_manage_stock' => 1, 'qty' => 100, 'is_qty_decimal' => 0, 'is_in_stock' => 1] - ); + /** @var $product Product */ + $product = Bootstrap::getObjectManager()->create(Product::class); + $product->setTypeId(Type::TYPE_SIMPLE) + ->setId(1) + ->setAttributeSetId(4) + ->setWebsiteIds([1]) + ->setName('Simple Product') + ->setSku('simple') + ->setPrice(10) + ->setDescription('Description with html tag') + ->setVisibility(Visibility::VISIBILITY_BOTH) + ->setStatus(Status::STATUS_ENABLED) + ->setCategoryIds([2]) + ->setStockData(['use_config_manage_stock' => 1, 'qty' => 100, 'is_qty_decimal' => 0, 'is_in_stock' => 1]); + return $product; } } diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/CopierTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/CopierTest.php index 6510e048f0e2d..9444f5914c944 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/CopierTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/CopierTest.php @@ -7,36 +7,62 @@ namespace Magento\Catalog\Model\Product; -use Magento\Catalog\Model\ProductRepository; +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Catalog\Model\ProductFactory; use Magento\Store\Model\Store; use Magento\TestFramework\Helper\Bootstrap; use PHPUnit\Framework\TestCase; /** * Tests product copier. + * @magentoAppArea adminhtml */ class CopierTest extends TestCase { + /** + * @var Copier + */ + private $copier; + + /** + * @var ProductRepositoryInterface + */ + private $productRepository; + + /** + * @var ProductFactory + */ + private $productFactory; + + /** + * @inheritdoc + */ + protected function setUp(): void + { + $objectManager = Bootstrap::getObjectManager(); + $this->copier = $objectManager->get(Copier::class); + $this->productRepository = $objectManager->get(ProductRepositoryInterface::class); + $this->productFactory = $objectManager->get(ProductFactory::class); + } + /** * Tests copying of product. * * Case when url_key is set for store view and has equal value to default store. * * @magentoDataFixture Magento/Catalog/_files/product_simple_multistore_with_url_key.php - * @magentoAppArea adminhtml + * + * @return void */ - public function testProductCopyWithExistingUrlKey() + public function testProductCopyWithExistingUrlKey(): void { $productSKU = 'simple_100'; - /** @var ProductRepository $productRepository */ - $productRepository = Bootstrap::getObjectManager()->get(ProductRepository::class); - $copier = Bootstrap::getObjectManager()->get(Copier::class); + $product = $this->productRepository->get($productSKU); + $newProduct = $this->productFactory->create(); + $duplicate = $this->copier->copy($product, $newProduct); - $product = $productRepository->get($productSKU); - $duplicate = $copier->copy($product); - - $duplicateStoreView = $productRepository->getById($duplicate->getId(), false, Store::DISTRO_STORE_ID); - $productStoreView = $productRepository->get($productSKU, false, Store::DISTRO_STORE_ID); + $duplicateStoreView = $this->productRepository->getById($duplicate->getId(), false, Store::DISTRO_STORE_ID); + $productStoreView = $this->productRepository->get($productSKU, false, Store::DISTRO_STORE_ID); $this->assertNotEquals( $duplicateStoreView->getUrlKey(), @@ -44,4 +70,30 @@ public function testProductCopyWithExistingUrlKey() 'url_key of product duplicate should be different then url_key of the product for the same store view' ); } + + /** + * Tests copying of product when url_key exists. + * + * @magentoDataFixture Magento/CatalogUrlRewrite/_files/product_simple.php + * @magentoDbIsolation disabled + * + * @return void + */ + public function testProductCopyWithExistingUrlKeyPermanentType(): void + { + $product = $this->productRepository->get('simple'); + $duplicate = $this->copier->copy($product, $this->productFactory->create()); + + $data = [ + 'url_key' => 'new-url-key', + 'url_key_create_redirect' => $duplicate->getUrlKey(), + 'save_rewrites_history' => true, + ]; + $duplicate->addData($data); + $this->productRepository->save($duplicate); + + $secondDuplicate = $this->copier->copy($product, $this->productFactory->create()); + + $this->assertNotNull($secondDuplicate->getId()); + } } diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/ProductTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/ProductTest.php index 8acb243a706c2..47d0d9e77d11e 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/ProductTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/ProductTest.php @@ -40,18 +40,23 @@ class ProductTest extends \PHPUnit\Framework\TestCase /** * @var ProductRepositoryInterface */ - protected $productRepository; + private $productRepository; /** * @var Product */ - protected $_model; + private $model; /** * @var ObjectManagerInterface */ private $objectManager; + /** + * @var ProductFactory + */ + private $productFactory; + /** * @inheritdoc */ @@ -59,7 +64,8 @@ protected function setUp(): void { $this->objectManager = Bootstrap::getObjectManager(); $this->productRepository = $this->objectManager->create(ProductRepositoryInterface::class); - $this->_model = $this->objectManager->create(Product::class); + $this->model = $this->objectManager->create(Product::class); + $this->productFactory = $this->objectManager->create(ProductFactory::class); } /** @@ -93,9 +99,9 @@ public static function tearDownAfterClass(): void */ public function testCanAffectOptions() { - $this->assertFalse($this->_model->canAffectOptions()); - $this->_model->canAffectOptions(true); - $this->assertTrue($this->_model->canAffectOptions()); + $this->assertFalse($this->model->canAffectOptions()); + $this->model->canAffectOptions(true); + $this->assertTrue($this->model->canAffectOptions()); } /** @@ -107,7 +113,7 @@ public function testCanAffectOptions() */ public function testCRUD() { - $this->_model->setTypeId( + $this->model->setTypeId( 'simple' )->setAttributeSetId( 4 @@ -128,7 +134,7 @@ public function testCRUD() )->setStatus( Status::STATUS_ENABLED ); - $crud = new \Magento\TestFramework\Entity($this->_model, ['sku' => uniqid()]); + $crud = new \Magento\TestFramework\Entity($this->model, ['sku' => uniqid()]); $crud->testCrud(); } @@ -150,7 +156,7 @@ public function testMaximumDescriptionLength() $random = Bootstrap::getObjectManager()->get(Random::class); $longDescription = $random->getRandomString(70000); - $this->_model->setTypeId( + $this->model->setTypeId( 'simple' )->setAttributeSetId( 4 @@ -174,7 +180,7 @@ public function testMaximumDescriptionLength() Status::STATUS_ENABLED ); - $this->productRepository->save($this->_model); + $this->productRepository->save($this->model); $product = $this->productRepository->get($sku); $this->assertEquals($longDescription, $product->getDescription()); @@ -195,7 +201,7 @@ public function testCleanCache() ['catalog_product_999'] ); // potential bug: it cleans by cache tags, generated from its ID, which doesn't make much sense - $this->_model->setId(999)->cleanCache(); + $this->model->setId(999)->cleanCache(); $this->assertFalse( \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( \Magento\Framework\App\CacheInterface::class @@ -215,8 +221,8 @@ public function testAddImageToMediaGallery() // Model accepts only files in tmp media path, we need to copy fixture file there $mediaFile = $this->_copyFileToBaseTmpMediaPath(dirname(__DIR__) . '/_files/magento_image.jpg'); - $this->_model->addImageToMediaGallery($mediaFile); - $gallery = $this->_model->getData('media_gallery'); + $this->model->addImageToMediaGallery($mediaFile); + $gallery = $this->model->getData('media_gallery'); $this->assertNotEmpty($gallery); $this->assertTrue(isset($gallery['images'][0]['file'])); $this->assertStringStartsWith('/m/a/magento_image', $gallery['images'][0]['file']); @@ -259,18 +265,18 @@ protected function _copyFileToBaseTmpMediaPath($sourceFile) */ public function testDuplicate() { - $this->_model = $this->productRepository->get('simple'); + $this->model = $this->productRepository->get('simple'); // fixture /** @var \Magento\Catalog\Model\Product\Copier $copier */ $copier = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( \Magento\Catalog\Model\Product\Copier::class ); - $duplicate = $copier->copy($this->_model); + $duplicate = $copier->copy($this->model, $this->productFactory->create()); try { $this->assertNotEmpty($duplicate->getId()); - $this->assertNotEquals($duplicate->getId(), $this->_model->getId()); - $this->assertNotEquals($duplicate->getSku(), $this->_model->getSku()); + $this->assertNotEquals($duplicate->getId(), $this->model->getId()); + $this->assertNotEquals($duplicate->getSku(), $this->model->getSku()); $this->assertEquals( Status::STATUS_DISABLED, $duplicate->getStatus() @@ -290,14 +296,14 @@ public function testDuplicate() */ public function testDuplicateSkuGeneration() { - $this->_model = $this->productRepository->get('simple'); + $this->model = $this->productRepository->get('simple'); - $this->assertEquals('simple', $this->_model->getSku()); + $this->assertEquals('simple', $this->model->getSku()); /** @var \Magento\Catalog\Model\Product\Copier $copier */ $copier = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( \Magento\Catalog\Model\Product\Copier::class ); - $duplicate = $copier->copy($this->_model); + $duplicate = $copier->copy($this->model, $this->productFactory->create()); $this->assertEquals('simple-5', $duplicate->getSku()); } @@ -329,18 +335,18 @@ public function testVisibilityApi() { $this->assertEquals( [Status::STATUS_ENABLED], - $this->_model->getVisibleInCatalogStatuses() + $this->model->getVisibleInCatalogStatuses() ); $this->assertEquals( [Status::STATUS_ENABLED], - $this->_model->getVisibleStatuses() + $this->model->getVisibleStatuses() ); - $this->_model->setStatus(Status::STATUS_DISABLED); - $this->assertFalse($this->_model->isVisibleInCatalog()); + $this->model->setStatus(Status::STATUS_DISABLED); + $this->assertFalse($this->model->isVisibleInCatalog()); - $this->_model->setStatus(Status::STATUS_ENABLED); - $this->assertTrue($this->_model->isVisibleInCatalog()); + $this->model->setStatus(Status::STATUS_ENABLED); + $this->assertTrue($this->model->isVisibleInCatalog()); $this->assertEquals( [ @@ -348,16 +354,16 @@ public function testVisibilityApi() Visibility::VISIBILITY_IN_CATALOG, Visibility::VISIBILITY_BOTH, ], - $this->_model->getVisibleInSiteVisibilities() + $this->model->getVisibleInSiteVisibilities() ); - $this->assertFalse($this->_model->isVisibleInSiteVisibility()); - $this->_model->setVisibility(Visibility::VISIBILITY_IN_SEARCH); - $this->assertTrue($this->_model->isVisibleInSiteVisibility()); - $this->_model->setVisibility(Visibility::VISIBILITY_IN_CATALOG); - $this->assertTrue($this->_model->isVisibleInSiteVisibility()); - $this->_model->setVisibility(Visibility::VISIBILITY_BOTH); - $this->assertTrue($this->_model->isVisibleInSiteVisibility()); + $this->assertFalse($this->model->isVisibleInSiteVisibility()); + $this->model->setVisibility(Visibility::VISIBILITY_IN_SEARCH); + $this->assertTrue($this->model->isVisibleInSiteVisibility()); + $this->model->setVisibility(Visibility::VISIBILITY_IN_CATALOG); + $this->assertTrue($this->model->isVisibleInSiteVisibility()); + $this->model->setVisibility(Visibility::VISIBILITY_BOTH); + $this->assertTrue($this->model->isVisibleInSiteVisibility()); } /** @@ -368,9 +374,9 @@ public function testVisibilityApi() */ public function testIsDuplicable() { - $this->assertTrue($this->_model->isDuplicable()); - $this->_model->setIsDuplicable(0); - $this->assertFalse($this->_model->isDuplicable()); + $this->assertTrue($this->model->isDuplicable()); + $this->model->setIsDuplicable(0); + $this->assertFalse($this->model->isDuplicable()); } /** @@ -383,13 +389,13 @@ public function testIsDuplicable() */ public function testIsSalable() { - $this->_model = $this->productRepository->get('simple'); + $this->model = $this->productRepository->get('simple'); // fixture - $this->assertTrue((bool) $this->_model->isSalable()); - $this->assertTrue((bool) $this->_model->isSaleable()); - $this->assertTrue((bool) $this->_model->isAvailable()); - $this->assertTrue($this->_model->isInStock()); + $this->assertTrue((bool) $this->model->isSalable()); + $this->assertTrue((bool) $this->model->isSaleable()); + $this->assertTrue((bool) $this->model->isAvailable()); + $this->assertTrue($this->model->isInStock()); } /** @@ -402,13 +408,13 @@ public function testIsSalable() */ public function testIsNotSalableWhenStatusDisabled() { - $this->_model = $this->productRepository->get('simple'); + $this->model = $this->productRepository->get('simple'); - $this->_model->setStatus(0); - $this->assertFalse((bool) $this->_model->isSalable()); - $this->assertFalse((bool) $this->_model->isSaleable()); - $this->assertFalse((bool) $this->_model->isAvailable()); - $this->assertFalse($this->_model->isInStock()); + $this->model->setStatus(0); + $this->assertFalse((bool) $this->model->isSalable()); + $this->assertFalse((bool) $this->model->isSaleable()); + $this->assertFalse((bool) $this->model->isAvailable()); + $this->assertFalse($this->model->isInStock()); } /** @@ -419,8 +425,8 @@ public function testIsNotSalableWhenStatusDisabled() */ public function testIsVirtual() { - $this->assertFalse($this->_model->isVirtual()); - $this->assertFalse($this->_model->getIsVirtual()); + $this->assertFalse($this->model->isVirtual()); + $this->assertFalse($this->model->getIsVirtual()); /** @var $model \Magento\Catalog\Model\Product */ $model = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( @@ -438,9 +444,9 @@ public function testIsVirtual() */ public function testToArray() { - $this->assertEquals([], $this->_model->toArray()); - $this->_model->setSku('sku')->setName('name'); - $this->assertEquals(['sku' => 'sku', 'name' => 'name'], $this->_model->toArray()); + $this->assertEquals([], $this->model->toArray()); + $this->model->setSku('sku')->setName('name'); + $this->assertEquals(['sku' => 'sku', 'name' => 'name'], $this->model->toArray()); } /** @@ -450,8 +456,8 @@ public function testToArray() */ public function testFromArray() { - $this->_model->fromArray(['sku' => 'sku', 'name' => 'name', 'stock_item' => ['key' => 'value']]); - $this->assertEquals(['sku' => 'sku', 'name' => 'name'], $this->_model->getData()); + $this->model->fromArray(['sku' => 'sku', 'name' => 'name', 'stock_item' => ['key' => 'value']]); + $this->assertEquals(['sku' => 'sku', 'name' => 'name'], $this->model->getData()); } /** @@ -461,9 +467,9 @@ public function testFromArray() */ public function testSetOrigDataBackend() { - $this->assertEmpty($this->_model->getOrigData()); - $this->_model->setOrigData('key', 'value'); - $this->assertEquals('value', $this->_model->getOrigData('key')); + $this->assertEmpty($this->model->getOrigData()); + $this->model->setOrigData('key', 'value'); + $this->assertEquals('value', $this->model->getOrigData('key')); } /** @@ -473,24 +479,24 @@ public function testSetOrigDataBackend() */ public function testReset() { - $model = $this->_model; + $model = $this->model; $this->_assertEmpty($model); - $this->_model->setData('key', 'value'); - $this->_model->reset(); + $this->model->setData('key', 'value'); + $this->model->reset(); $this->_assertEmpty($model); - $this->_model->setOrigData('key', 'value'); - $this->_model->reset(); + $this->model->setOrigData('key', 'value'); + $this->model->reset(); $this->_assertEmpty($model); - $this->_model->addCustomOption('key', 'value'); - $this->_model->reset(); + $this->model->addCustomOption('key', 'value'); + $this->model->reset(); $this->_assertEmpty($model); - $this->_model->canAffectOptions(true); - $this->_model->reset(); + $this->model->canAffectOptions(true); + $this->model->reset(); $this->_assertEmpty($model); } @@ -519,7 +525,7 @@ public function testIsProductsHasSku() $product2 = $this->productRepository->get('simple2'); $this->assertTrue( - $this->_model->isProductsHasSku( + $this->model->isProductsHasSku( [$product1->getId(), $product2->getId()] ) ); @@ -533,7 +539,7 @@ public function testIsProductsHasSku() public function testProcessBuyRequest() { $request = new \Magento\Framework\DataObject(); - $result = $this->_model->processBuyRequest($request); + $result = $this->model->processBuyRequest($request); $this->assertInstanceOf(\Magento\Framework\DataObject::class, $result); $this->assertArrayHasKey('errors', $result->getData()); } @@ -545,7 +551,7 @@ public function testProcessBuyRequest() */ public function testValidate() { - $this->_model->setTypeId( + $this->model->setTypeId( 'simple' )->setAttributeSetId( 4 @@ -568,7 +574,7 @@ public function testValidate() )->setCollectExceptionMessages( true ); - $validationResult = $this->_model->validate(); + $validationResult = $this->model->validate(); $this->assertEquals('SKU length should be 64 characters maximum.', $validationResult['sku']); unset($validationResult['sku']); foreach ($validationResult as $error) { @@ -588,7 +594,7 @@ public function testValidateUniqueInputAttributeValue() $attribute = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() ->get(\Magento\Catalog\Model\ResourceModel\Eav\Attribute::class) ->loadByCode(\Magento\Catalog\Model\Product::ENTITY, 'unique_input_attribute'); - $this->_model->setTypeId( + $this->model->setTypeId( 'simple' )->setAttributeSetId( 4 @@ -611,7 +617,7 @@ public function testValidateUniqueInputAttributeValue() true ); - $validationResult = $this->_model->validate(); + $validationResult = $this->model->validate(); $this->assertCount(1, $validationResult); $this->assertContains( @@ -633,11 +639,11 @@ public function testValidateUniqueInputAttributeOnTheSameProduct() $attribute = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() ->get(\Magento\Catalog\Model\ResourceModel\Eav\Attribute::class) ->loadByCode(\Magento\Catalog\Model\Product::ENTITY, 'unique_input_attribute'); - $this->_model = $this->_model->loadByAttribute( + $this->model = $this->model->loadByAttribute( 'sku', 'simple product with unique input attribute' ); - $this->_model->setTypeId( + $this->model->setTypeId( 'simple' )->setAttributeSetId( 4 @@ -660,7 +666,7 @@ public function testValidateUniqueInputAttributeOnTheSameProduct() true ); - $validationResult = $this->_model->validate(); + $validationResult = $this->model->validate(); $this->assertTrue($validationResult); } @@ -672,8 +678,8 @@ public function testValidateUniqueInputAttributeOnTheSameProduct() */ public function testGetOptions() { - $this->_model = $this->productRepository->get('simple_with_custom_options'); - $options = $this->_model->getOptions(); + $this->model = $this->productRepository->get('simple_with_custom_options'); + $options = $this->model->getOptions(); $this->assertNotEmpty($options); $expectedValue = [ '3-1-select' => -3000.00,