From 82391e66b38fc80c4396d614036e2bb503d6f8a0 Mon Sep 17 00:00:00 2001 From: Valeriy Nayda Date: Mon, 13 Mar 2017 13:01:46 +0200 Subject: [PATCH 1/7] MAGETWO-64882: [Performance] Product special price calculation/rendering on Category page --- .../Catalog/Block/Product/ListProduct.php | 6 +- .../Catalog/Pricing/Render/FinalPriceBox.php | 13 ++ .../Unit/Block/Product/ListProductTest.php | 55 ++++++++ .../Unit/Pricing/Render/FinalPriceBoxTest.php | 57 ++++++++- .../templates/product/price/final_price.phtml | 2 +- .../RenderingBasedOnIsProductListFlagTest.php | 109 ++++++++++++++++ .../RenderingBasedOnIsProductListFlagTest.php | 120 ++++++++++++++++++ 7 files changed, 359 insertions(+), 3 deletions(-) create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/Pricing/Render/FinalPriceBox/RenderingBasedOnIsProductListFlagTest.php create mode 100644 dev/tests/integration/testsuite/Magento/ConfigurableProduct/Pricing/Render/FinalPriceBox/RenderingBasedOnIsProductListFlagTest.php diff --git a/app/code/Magento/Catalog/Block/Product/ListProduct.php b/app/code/Magento/Catalog/Block/Product/ListProduct.php index 980c34de55391..e0947ef0ce049 100644 --- a/app/code/Magento/Catalog/Block/Product/ListProduct.php +++ b/app/code/Magento/Catalog/Block/Product/ListProduct.php @@ -317,11 +317,15 @@ public function getProductPrice(\Magento\Catalog\Model\Product $product) } /** + * Specifies that price rendering should be done for the list of products + * i.e. rendering happens in the scope of product list, but not single product + * * @return \Magento\Framework\Pricing\Render */ protected function getPriceRender() { - return $this->getLayout()->getBlock('product.price.render.default'); + return $this->getLayout()->getBlock('product.price.render.default') + ->setData('is_product_list', true); } /** diff --git a/app/code/Magento/Catalog/Pricing/Render/FinalPriceBox.php b/app/code/Magento/Catalog/Pricing/Render/FinalPriceBox.php index b56f3a493d691..f370c49cdfa20 100644 --- a/app/code/Magento/Catalog/Pricing/Render/FinalPriceBox.php +++ b/app/code/Magento/Catalog/Pricing/Render/FinalPriceBox.php @@ -193,6 +193,19 @@ public function getCacheKeyInfo() { $cacheKeys = parent::getCacheKeyInfo(); $cacheKeys['display_minimal_price'] = $this->getDisplayMinimalPrice(); + $cacheKeys['is_product_list'] = $this->isProductList(); return $cacheKeys; } + + /** + * Get flag that price rendering should be done for the list of products + * By default (if flag is not set) is false + * + * @return bool + */ + public function isProductList() + { + $isProductList = $this->getData('is_product_list'); + return $isProductList === true; + } } diff --git a/app/code/Magento/Catalog/Test/Unit/Block/Product/ListProductTest.php b/app/code/Magento/Catalog/Test/Unit/Block/Product/ListProductTest.php index f0dc7d2c706ae..03b49804b75c2 100644 --- a/app/code/Magento/Catalog/Test/Unit/Block/Product/ListProductTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Block/Product/ListProductTest.php @@ -5,6 +5,10 @@ */ namespace Magento\Catalog\Test\Unit\Block\Product; +use Magento\Catalog\Block\Product\Context; +use Magento\Framework\Pricing\Render; +use Magento\Framework\View\LayoutInterface; + /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ @@ -70,6 +74,21 @@ class ListProductTest extends \PHPUnit_Framework_TestCase */ protected $toolbarMock; + /** + * @var LayoutInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $layout; + + /** + * @var Context|\PHPUnit_Framework_MockObject_MockObject + */ + private $context; + + /** + * @var Render|\PHPUnit_Framework_MockObject_MockObject + */ + private $renderer; + protected function setUp() { $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); @@ -143,10 +162,32 @@ protected function setUp() $this->urlHelperMock = $this->getMockBuilder(\Magento\Framework\Url\Helper\Data::class) ->disableOriginalConstructor()->getMock(); + + $this->layout = $this->getMockBuilder(LayoutInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->context = $this->getMockBuilder(Context::class) + ->disableOriginalConstructor() + ->getMock(); + $this->renderer = $this->getMockBuilder(Render::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->context->expects($this->any()) + ->method('getRegistry') + ->willReturn($this->registryMock); + $this->context->expects($this->any()) + ->method('getCartHelper') + ->willReturn($this->cartHelperMock); + $this->context->expects($this->any()) + ->method('getLayout') + ->willReturn($this->layout); + $this->block = $objectManager->getObject( \Magento\Catalog\Block\Product\ListProduct::class, [ 'registry' => $this->registryMock, + 'context' => $this->context, 'layerResolver' => $layerResolver, 'cartHelper' => $this->cartHelperMock, 'postDataHelper' => $this->postDataHelperMock, @@ -257,4 +298,18 @@ public function testGetAddToCartPostParams() $result = $this->block->getAddToCartPostParams($this->productMock); $this->assertEquals($expectedPostData, $result); } + + public function testSetIsProductListFlagOnGetProductPrice() + { + $this->renderer->expects($this->once()) + ->method('setData') + ->with('is_product_list', true) + ->willReturnSelf(); + $this->layout->expects($this->once()) + ->method('getBlock') + ->with('product.price.render.default') + ->willReturn($this->renderer); + + $this->block->getProductPrice($this->productMock); + } } diff --git a/app/code/Magento/Catalog/Test/Unit/Pricing/Render/FinalPriceBoxTest.php b/app/code/Magento/Catalog/Test/Unit/Pricing/Render/FinalPriceBoxTest.php index 96c34d86292f1..4a380fde70616 100644 --- a/app/code/Magento/Catalog/Test/Unit/Pricing/Render/FinalPriceBoxTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Pricing/Render/FinalPriceBoxTest.php @@ -401,8 +401,63 @@ public function testGetCacheKey() $this->assertStringEndsWith('list-category-page', $result); } - public function testGetCacheKeyInfo() + public function testGetCacheKeyInfoContainsDisplayMinimalPrice() { $this->assertArrayHasKey('display_minimal_price', $this->object->getCacheKeyInfo()); } + + /** + * Test when is_product_list flag is not specified + */ + public function testGetCacheKeyInfoContainsIsProductListFlagByDefault() + { + $cacheInfo = $this->object->getCacheKeyInfo(); + self::assertArrayHasKey('is_product_list', $cacheInfo); + self::assertFalse($cacheInfo['is_product_list']); + } + + /** + * Test when is_product_list flag is specified + * + * @param bool $flag + * @dataProvider isProductListDataProvider + */ + public function testGetCacheKeyInfoContainsIsProductListFlag($flag) + { + $this->object->setData('is_product_list', $flag); + $cacheInfo = $this->object->getCacheKeyInfo(); + self::assertArrayHasKey('is_product_list', $cacheInfo); + self::assertEquals($flag, $cacheInfo['is_product_list']); + } + + /** + * Test when is_product_list flag is not specified + */ + public function testIsProductListByDefault() + { + self::assertFalse($this->object->isProductList()); + } + + /** + * Test when is_product_list flag is specified + * + * @param bool $flag + * @dataProvider isProductListDataProvider + */ + public function testIsProductList($flag) + { + $this->object->setData('is_product_list', $flag); + self::assertEquals($flag, $this->object->isProductList()); + } + + /** + * @return array + */ + public function isProductListDataProvider() + { + return [ + 'is_not_product_list' => [false], + 'is_product_list' => [true], + ]; + } } diff --git a/app/code/Magento/ConfigurableProduct/view/base/templates/product/price/final_price.phtml b/app/code/Magento/ConfigurableProduct/view/base/templates/product/price/final_price.phtml index a1cbf4a7adde5..d39f76d2a21bb 100644 --- a/app/code/Magento/ConfigurableProduct/view/base/templates/product/price/final_price.phtml +++ b/app/code/Magento/ConfigurableProduct/view/base/templates/product/price/final_price.phtml @@ -19,7 +19,7 @@ $finalPriceModel = $block->getPriceType('final_price'); $idSuffix = $block->getIdSuffix() ? $block->getIdSuffix() : ''; $schema = ($block->getZone() == 'item_view') ? true : false; ?> -hasSpecialPrice()): ?> +isProductList() && $block->hasSpecialPrice()): ?> renderAmount($finalPriceModel->getAmount(), [ 'display_label' => __('Special Price'), diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Pricing/Render/FinalPriceBox/RenderingBasedOnIsProductListFlagTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Pricing/Render/FinalPriceBox/RenderingBasedOnIsProductListFlagTest.php new file mode 100644 index 0000000000000..6f1f1b46290da --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/Pricing/Render/FinalPriceBox/RenderingBasedOnIsProductListFlagTest.php @@ -0,0 +1,109 @@ +get(ProductRepositoryInterface::class); + $this->product = $productRepository->get('simple'); + $this->finalPrice = Bootstrap::getObjectManager()->create(FinalPrice::class, [ + 'saleableItem' => $this->product, + 'quantity' => null + ]); + $this->rendererPool = Bootstrap::getObjectManager()->create(RendererPool::class); + $this->rendererPool->setData( + [ + 'default' => + [ + 'default_amount_render_class' => Amount::class, + 'default_amount_render_template' => 'Magento_Catalog::product/price/amount/default.phtml', + ], + ] + ); + $this->finalPriceBox = Bootstrap::getObjectManager()->create(FinalPriceBox::class, [ + 'saleableItem' => $this->product, + 'price' => $this->finalPrice, + 'rendererPool' => $this->rendererPool, + ]); + $this->finalPriceBox->setTemplate('Magento_Catalog::product/price/final_price.phtml'); + } + + /** + * Test when is_product_list flag is not specified. Regular and Special price should be rendered + * + * @magentoDataFixture Magento/Catalog/_files/product_special_price.php + * @magentoAppArea frontend + */ + public function testRenderingByDefault() + { + $html = $this->finalPriceBox->toHtml(); + self::assertContains('5.99', $html); + self::assertSelectCount('.special-price', true, $html); + self::assertSelectCount('.old-price', true, $html); + } + + /** + * Test when is_product_list flag is specified. Regular and Special price should be rendered with any flag value + * For example should be rendered for product page and for list of products + * + * @param bool $flag + * @magentoDataFixture Magento/Catalog/_files/product_special_price.php + * @magentoAppArea frontend + * @dataProvider isProductListDataProvider + */ + public function testRenderingAccordingToIsProductListFlag($flag) + { + $this->finalPriceBox->setData('is_product_list', $flag); + $html = $this->finalPriceBox->toHtml(); + self::assertContains('5.99', $html); + self::assertSelectCount('.special-price', true, $html); + self::assertSelectCount('.old-price', true, $html); + } + + /** + * @return array + */ + public function isProductListDataProvider() + { + return [ + 'is_not_product_list' => [false], + 'is_product_list' => [true], + ]; + } +} diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Pricing/Render/FinalPriceBox/RenderingBasedOnIsProductListFlagTest.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Pricing/Render/FinalPriceBox/RenderingBasedOnIsProductListFlagTest.php new file mode 100644 index 0000000000000..3634082c54f7b --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Pricing/Render/FinalPriceBox/RenderingBasedOnIsProductListFlagTest.php @@ -0,0 +1,120 @@ +get(ProductRepositoryInterface::class); + $this->product = $productRepository->get('configurable'); + $this->finalPrice = Bootstrap::getObjectManager()->create(FinalPrice::class, [ + 'saleableItem' => $this->product, + 'quantity' => null + ]); + $this->rendererPool = Bootstrap::getObjectManager()->create(RendererPool::class); + $this->rendererPool->setData( + [ + 'default' => + [ + 'default_amount_render_class' => Amount::class, + 'default_amount_render_template' => 'Magento_Catalog::product/price/amount/default.phtml', + ], + ] + ); + $this->finalPriceBox = Bootstrap::getObjectManager()->create(FinalPriceBox::class, [ + 'saleableItem' => $this->product, + 'price' => $this->finalPrice, + 'rendererPool' => $this->rendererPool, + ]); + $this->finalPriceBox->setTemplate('Magento_ConfigurableProduct::product/price/final_price.phtml'); + + /** @var Product $childProduct */ + $childProduct = $productRepository->get('simple_10', true); + $childProduct->setData('special_price', 5.99); + $productRepository->save($childProduct); + } + + /** + * Test when is_product_list flag is not specified. Regular and Special price should be rendered + * + * @magentoDataFixture Magento/ConfigurableProduct/_files/product_configurable.php + * @magentoAppArea frontend + */ + public function testRenderingByDefault() + { + $html = $this->finalPriceBox->toHtml(); + self::assertContains('5.99', $html); + self::assertSelectCount('.special-price', true, $html); + self::assertSelectCount('.old-price', true, $html); + } + + /** + * Test when is_product_list flag is specified + * + * Special price should be valid + * FinalPriceBox::hasSpecialPrice should not be call + * Regular price for Configurable product should be rendered for is_product_list = false (product page), but not be + * for for is_product_list = true (list of products) + * + * @param bool $flag + * @param int|bool $count + * @magentoDataFixture Magento/ConfigurableProduct/_files/product_configurable.php + * @magentoAppArea frontend + * @dataProvider isProductListDataProvider + */ + public function testRenderingAccordingToIsProductListFlag($flag, $count) + { + $this->finalPriceBox->setData('is_product_list', $flag); + $html = $this->finalPriceBox->toHtml(); + self::assertContains('5.99', $html); + self::assertSelectCount('.special-price', $count, $html); + self::assertSelectCount('.old-price', $count, $html); + } + + /** + * @return array + */ + public function isProductListDataProvider() + { + return [ + 'is_not_product_list' => [false, true], + 'is_product_list' => [true, 0], + ]; + } +} From e992f45daee033d9f51d7a511a56b3694fabf6c6 Mon Sep 17 00:00:00 2001 From: Maksym Aposov Date: Mon, 20 Mar 2017 14:44:47 +0200 Subject: [PATCH 2/7] MAGETWO-64882: [Performance] Product special price calculation/rendering on Category page --- .../TestCase/ApplyCatalogPriceRulesTest.xml | 1 - ...sertCatalogPriceRuleAppliedCatalogPage.php | 95 +++++++++++++++++++ ...nfigurableProductCatalogPriceRulesTest.xml | 2 + 3 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 dev/tests/functional/tests/app/Magento/CatalogRuleConfigurable/Test/Constraint/AssertCatalogPriceRuleAppliedCatalogPage.php diff --git a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/TestCase/ApplyCatalogPriceRulesTest.xml b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/TestCase/ApplyCatalogPriceRulesTest.xml index 0726bb01a9976..523230ec1c76b 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/TestCase/ApplyCatalogPriceRulesTest.xml +++ b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/TestCase/ApplyCatalogPriceRulesTest.xml @@ -172,7 +172,6 @@ Fixed UK_address checkmo - diff --git a/dev/tests/functional/tests/app/Magento/CatalogRuleConfigurable/Test/Constraint/AssertCatalogPriceRuleAppliedCatalogPage.php b/dev/tests/functional/tests/app/Magento/CatalogRuleConfigurable/Test/Constraint/AssertCatalogPriceRuleAppliedCatalogPage.php new file mode 100644 index 0000000000000..74a52b474d6fa --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/CatalogRuleConfigurable/Test/Constraint/AssertCatalogPriceRuleAppliedCatalogPage.php @@ -0,0 +1,95 @@ +objectManager->create( + \Magento\Customer\Test\TestStep\LoginCustomerOnFrontendStep::class, + ['customer' => $customer] + )->run(); + } else { + $this->objectManager->create(\Magento\Customer\Test\TestStep\LogoutCustomerOnFrontendStep::class)->run(); + } + + $cmsIndexPage->open(); + foreach ($products as $key => $product) { + $categoryName = $product->getCategoryIds()[0]; + $cmsIndexPage->getTopmenu()->selectCategoryByName($categoryName); + $priceBlock = $catalogCategoryViewPage->getListProductBlock()->getProductItem($product)->getPriceBlock(); + \PHPUnit_Framework_Assert::assertTrue( + $priceBlock->isVisible(), + 'Price block is not displayed for product ' . $product->getName() + ); + // Product price with applied rule displayed as usual price for Configurable products (MAGETWO-64882) + $actualPrice['special'] = (float)$priceBlock->getPrice(); + $diff = $this->verifyData($actualPrice, $productPrice[$key]); + \PHPUnit_Framework_Assert::assertTrue( + empty($diff), + implode(' ', $diff) + ); + } + } + + /** + * Check if arrays have equal values. + * + * @param array $formData + * @param array $fixtureData + * @return array + */ + protected function verifyData(array $formData, array $fixtureData) + { + $errorMessage = []; + foreach ($formData as $key => $value) { + if ($value != $fixtureData[$key]) { + $errorMessage[] = "Value " . $key . " is not equal." + . "\nExpected: " . $fixtureData[$key] + . "\nActual: " . $value . "\n"; + } + } + return $errorMessage; + } + + /** + * Text of catalog price rule visibility on catalog page (frontend). + * + * @return string + */ + public function toString() + { + return 'Displayed catalog price rule data on catalog page(frontend) equals to passed from fixture.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/CatalogRuleConfigurable/Test/TestCase/ApplyConfigurableProductCatalogPriceRulesTest.xml b/dev/tests/functional/tests/app/Magento/CatalogRuleConfigurable/Test/TestCase/ApplyConfigurableProductCatalogPriceRulesTest.xml index c6eaeb61b4abb..2a9815b10ccd3 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogRuleConfigurable/Test/TestCase/ApplyConfigurableProductCatalogPriceRulesTest.xml +++ b/dev/tests/functional/tests/app/Magento/CatalogRuleConfigurable/Test/TestCase/ApplyConfigurableProductCatalogPriceRulesTest.xml @@ -34,6 +34,7 @@ Fixed UK_address checkmo + @@ -69,6 +70,7 @@ Fixed UK_address checkmo + From dc3a7c7f788e5184e02f3ec68fd83721a308b49f Mon Sep 17 00:00:00 2001 From: Maksym Aposov Date: Mon, 20 Mar 2017 15:08:47 +0200 Subject: [PATCH 3/7] MAGETWO-64882: [Performance] Product special price calculation/rendering on Category page --- .../ApplyConfigurableProductCatalogPriceRulesTest.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dev/tests/functional/tests/app/Magento/CatalogRuleConfigurable/Test/TestCase/ApplyConfigurableProductCatalogPriceRulesTest.xml b/dev/tests/functional/tests/app/Magento/CatalogRuleConfigurable/Test/TestCase/ApplyConfigurableProductCatalogPriceRulesTest.xml index 2a9815b10ccd3..2e9e2480f382f 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogRuleConfigurable/Test/TestCase/ApplyConfigurableProductCatalogPriceRulesTest.xml +++ b/dev/tests/functional/tests/app/Magento/CatalogRuleConfigurable/Test/TestCase/ApplyConfigurableProductCatalogPriceRulesTest.xml @@ -34,7 +34,7 @@ Fixed UK_address checkmo - + @@ -70,7 +70,7 @@ Fixed UK_address checkmo - + From 412777ebf1b8617ef245ccf0ce46a3d06885fb93 Mon Sep 17 00:00:00 2001 From: Maksym Aposov Date: Wed, 22 Mar 2017 13:12:53 +0200 Subject: [PATCH 4/7] MAGETWO-64882: [Performance] Product special price calculation/rendering on Category page - Fix Static tests after merge --- .../Unit/Block/Product/ListProductTest.php | 41 ++++++------------- 1 file changed, 12 insertions(+), 29 deletions(-) diff --git a/app/code/Magento/Catalog/Test/Unit/Block/Product/ListProductTest.php b/app/code/Magento/Catalog/Test/Unit/Block/Product/ListProductTest.php index 03b49804b75c2..0b9a823c5e38a 100644 --- a/app/code/Magento/Catalog/Test/Unit/Block/Product/ListProductTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Block/Product/ListProductTest.php @@ -6,7 +6,9 @@ namespace Magento\Catalog\Test\Unit\Block\Product; use Magento\Catalog\Block\Product\Context; +use Magento\Framework\Event\ManagerInterface; use Magento\Framework\Pricing\Render; +use Magento\Framework\Url\Helper\Data; use Magento\Framework\View\LayoutInterface; /** @@ -50,7 +52,7 @@ class ListProductTest extends \PHPUnit_Framework_TestCase protected $typeInstanceMock; /** - * @var \Magento\Framework\Url\Helper\Data | \PHPUnit_Framework_MockObject_MockObject + * @var Data | \PHPUnit_Framework_MockObject_MockObject */ protected $urlHelperMock; @@ -74,11 +76,6 @@ class ListProductTest extends \PHPUnit_Framework_TestCase */ protected $toolbarMock; - /** - * @var LayoutInterface|\PHPUnit_Framework_MockObject_MockObject - */ - private $layout; - /** * @var Context|\PHPUnit_Framework_MockObject_MockObject */ @@ -160,28 +157,15 @@ protected function setUp() false ); - $this->urlHelperMock = $this->getMockBuilder(\Magento\Framework\Url\Helper\Data::class) - ->disableOriginalConstructor()->getMock(); + $this->urlHelperMock = $this->getMockBuilder(Data::class)->disableOriginalConstructor()->getMock(); + $this->context = $this->getMockBuilder(Context::class)->disableOriginalConstructor()->getMock(); + $this->renderer = $this->getMockBuilder(Render::class)->disableOriginalConstructor()->getMock(); + $eventManager = $this->getMockForAbstractClass(ManagerInterface::class, [], '', false); - $this->layout = $this->getMockBuilder(LayoutInterface::class) - ->disableOriginalConstructor() - ->getMock(); - $this->context = $this->getMockBuilder(Context::class) - ->disableOriginalConstructor() - ->getMock(); - $this->renderer = $this->getMockBuilder(Render::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->context->expects($this->any()) - ->method('getRegistry') - ->willReturn($this->registryMock); - $this->context->expects($this->any()) - ->method('getCartHelper') - ->willReturn($this->cartHelperMock); - $this->context->expects($this->any()) - ->method('getLayout') - ->willReturn($this->layout); + $this->context->expects($this->any())->method('getRegistry')->willReturn($this->registryMock); + $this->context->expects($this->any())->method('getCartHelper')->willReturn($this->cartHelperMock); + $this->context->expects($this->any())->method('getLayout')->willReturn($this->layoutMock); + $this->context->expects($this->any())->method('getEventManager')->willReturn($eventManager); $this->block = $objectManager->getObject( \Magento\Catalog\Block\Product\ListProduct::class, @@ -195,7 +179,6 @@ protected function setUp() ] ); $this->block->setToolbarBlockName('mock'); - $this->block->setLayout($this->layoutMock); } protected function tearDown() @@ -305,7 +288,7 @@ public function testSetIsProductListFlagOnGetProductPrice() ->method('setData') ->with('is_product_list', true) ->willReturnSelf(); - $this->layout->expects($this->once()) + $this->layoutMock->expects($this->once()) ->method('getBlock') ->with('product.price.render.default') ->willReturn($this->renderer); From 3aa119fb29a740f95b40bfbc36d53b28ff8c5a0b Mon Sep 17 00:00:00 2001 From: Valeriy Nayda Date: Mon, 13 Mar 2017 16:57:17 +0200 Subject: [PATCH 5/7] MAGETWO-65095: [Performance] Redundant objects created for configurable product --- .../Model/Product/Type/Configurable.php | 17 ++++-- .../Model/Product/Type/ConfigurableTest.php | 54 +++++++++++++++++++ 2 files changed, 68 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable.php b/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable.php index 40ae7f5498c30..7adf99a559c5d 100644 --- a/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable.php +++ b/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable.php @@ -7,6 +7,7 @@ use Magento\Catalog\Api\Data\ProductAttributeInterface; use Magento\Catalog\Api\Data\ProductInterface; +use Magento\Catalog\Api\Data\ProductInterfaceFactory; use Magento\Catalog\Api\ProductRepositoryInterface; use Magento\Catalog\Model\Config; use Magento\Framework\App\ObjectManager; @@ -163,6 +164,11 @@ class Configurable extends \Magento\Catalog\Model\Product\Type\AbstractType */ private $customerSession; + /** + * @var ProductInterfaceFactory + */ + private $productFactory; + /** * @codingStandardsIgnoreStart/End * @@ -184,6 +190,7 @@ class Configurable extends \Magento\Catalog\Model\Product\Type\AbstractType * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig * @param \Magento\Framework\Api\ExtensionAttribute\JoinProcessorInterface $extensionAttributesJoinProcessor * @param \Magento\Framework\Serialize\Serializer\Json $serializer + * @param ProductInterfaceFactory $productFactory * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( @@ -206,7 +213,8 @@ public function __construct( \Magento\Framework\Api\ExtensionAttribute\JoinProcessorInterface $extensionAttributesJoinProcessor, \Magento\Framework\Cache\FrontendInterface $cache = null, \Magento\Customer\Model\Session $customerSession = null, - \Magento\Framework\Serialize\Serializer\Json $serializer = null + \Magento\Framework\Serialize\Serializer\Json $serializer = null, + ProductInterfaceFactory $productFactory = null ) { $this->typeConfigurableFactory = $typeConfigurableFactory; $this->_eavAttributeFactory = $eavAttributeFactory; @@ -218,6 +226,8 @@ public function __construct( $this->extensionAttributesJoinProcessor = $extensionAttributesJoinProcessor; $this->cache = $cache; $this->customerSession = $customerSession; + $this->productFactory = $productFactory ?: ObjectManager::getInstance() + ->get(ProductInterfaceFactory::class); parent::__construct( $catalogProductOption, $eavConfig, @@ -529,15 +539,16 @@ public function getUsedProducts($product, $requiredAttributeIds = null) ] ) ); - $collection = $this->getUsedProductCollection($product); $data = $this->serializer->unserialize($this->getCache()->load($key)); if (!empty($data)) { $usedProducts = []; foreach ($data as $item) { - $productItem = $collection->getNewEmptyItem()->setData($item); + $productItem = $this->productFactory->create(); + $productItem->setData($item); $usedProducts[] = $productItem; } } else { + $collection = $this->getUsedProductCollection($product); $collection ->setFlag('has_stock_status_filter', true) ->addAttributeToSelect($this->getCatalogConfig()->getProductAttributes()) diff --git a/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Product/Type/ConfigurableTest.php b/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Product/Type/ConfigurableTest.php index b8ef5b6dc0008..0cf814b2bb74d 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Product/Type/ConfigurableTest.php +++ b/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Product/Type/ConfigurableTest.php @@ -110,6 +110,11 @@ class ConfigurableTest extends \PHPUnit_Framework_TestCase */ protected $catalogConfig; + /** + * @var \Magento\Catalog\Api\Data\ProductInterfaceFactory|\PHPUnit_Framework_MockObject_MockObject + */ + private $productFactory; + /** * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ @@ -177,6 +182,10 @@ protected function setUp() ->method('getMetadata') ->with(ProductInterface::class) ->willReturn($this->entityMetadata); + $this->productFactory = $this->getMockBuilder(\Magento\Catalog\Api\Data\ProductInterfaceFactory::class) + ->setMethods(['create']) + ->disableOriginalConstructor() + ->getMock(); $this->_model = $this->_objectHelper->getObject( Configurable::class, @@ -197,6 +206,7 @@ protected function setUp() 'cache' => $this->cache, 'catalogConfig' => $this->catalogConfig, 'serializer' => $this->serializer, + 'productFactory' => $this->productFactory, ] ); $refClass = new \ReflectionClass(Configurable::class); @@ -374,6 +384,50 @@ public function testGetUsedProducts() $this->_model->getUsedProducts($product); } + public function testGetUsedProductsWithDataInCache() + { + $product = $this->getMockBuilder(\Magento\Catalog\Model\Product::class) + ->disableOriginalConstructor() + ->getMock(); + $childProduct = $this->getMockBuilder(\Magento\Catalog\Model\Product::class) + ->disableOriginalConstructor() + ->getMock(); + + $dataKey = '_cache_instance_products'; + $usedProductsData = [['first']]; + $usedProducts = [$childProduct]; + + $product->expects($this->once()) + ->method('hasData') + ->with($dataKey) + ->willReturn(false); + $product->expects($this->once()) + ->method('setData') + ->with($dataKey, $usedProducts); + $product->expects($this->any()) + ->method('getData') + ->willReturnOnConsecutiveCalls(1, $usedProducts); + + $childProduct->expects($this->once()) + ->method('setData') + ->with($usedProductsData[0]); + + $this->productFactory->expects($this->once()) + ->method('create') + ->willReturn($childProduct); + + $this->cache->expects($this->once()) + ->method('load') + ->willReturn($usedProductsData); + + $this->serializer->expects($this->once()) + ->method('unserialize') + ->with($usedProductsData) + ->willReturn($usedProductsData); + + self::assertEquals($usedProducts, $this->_model->getUsedProducts($product)); + } + /** * @param int $productStore * From 87cfbf3b247bc80fe96186e0727ad0c3d4daeadc Mon Sep 17 00:00:00 2001 From: Valeriy Nayda Date: Mon, 13 Mar 2017 17:32:20 +0200 Subject: [PATCH 6/7] MAGETWO-65095: [Performance] Redundant objects created for configurable product --- .../Test/Unit/Model/Product/Type/ConfigurableTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Product/Type/ConfigurableTest.php b/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Product/Type/ConfigurableTest.php index 0cf814b2bb74d..0630981f0b874 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Product/Type/ConfigurableTest.php +++ b/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Product/Type/ConfigurableTest.php @@ -30,6 +30,7 @@ * * @SuppressWarnings(PHPMD.LongVariable) * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + * @SuppressWarnings(PHPMD.TooManyFields) */ class ConfigurableTest extends \PHPUnit_Framework_TestCase { From 33cfaf7815470e355404b3529e2a88dde7b49a4c Mon Sep 17 00:00:00 2001 From: Valeriy Nayda Date: Fri, 31 Mar 2017 12:24:04 +0300 Subject: [PATCH 7/7] MAGETWO-64882: [Performance] Product special price calculation/rendering on Category page -- fix copyrights after merge --- .../Constraint/AssertCatalogPriceRuleAppliedCatalogPage.php | 1 - .../Constraint/AssertCatalogPriceRuleAppliedCatalogPage.php | 3 +-- .../FinalPriceBox/RenderingBasedOnIsProductListFlagTest.php | 2 +- .../FinalPriceBox/RenderingBasedOnIsProductListFlagTest.php | 2 +- 4 files changed, 3 insertions(+), 5 deletions(-) diff --git a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleAppliedCatalogPage.php b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleAppliedCatalogPage.php index 76973e9fa6777..51a78f4d4ad91 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleAppliedCatalogPage.php +++ b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleAppliedCatalogPage.php @@ -3,7 +3,6 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ - namespace Magento\CatalogRule\Test\Constraint; use Magento\Cms\Test\Page\CmsIndex; diff --git a/dev/tests/functional/tests/app/Magento/CatalogRuleConfigurable/Test/Constraint/AssertCatalogPriceRuleAppliedCatalogPage.php b/dev/tests/functional/tests/app/Magento/CatalogRuleConfigurable/Test/Constraint/AssertCatalogPriceRuleAppliedCatalogPage.php index 74a52b474d6fa..aa2c42b994402 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogRuleConfigurable/Test/Constraint/AssertCatalogPriceRuleAppliedCatalogPage.php +++ b/dev/tests/functional/tests/app/Magento/CatalogRuleConfigurable/Test/Constraint/AssertCatalogPriceRuleAppliedCatalogPage.php @@ -1,9 +1,8 @@