Skip to content

Commit

Permalink
Merge commit 'refs/pull/1566/head' of github.com:magento/magento2ce i…
Browse files Browse the repository at this point in the history
…nto 2.2-develop
  • Loading branch information
Andrey Konosov committed Oct 10, 2017
2 parents 30a16fa + 4ed54d7 commit dfd934f
Show file tree
Hide file tree
Showing 9 changed files with 414 additions and 14 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\ConfigurableProduct\Model\ResourceModel\Product;

use Magento\Catalog\Model\ResourceModel\Product\BaseSelectProcessorInterface;
use Magento\Catalog\Model\ResourceModel\Product\LinkedProductSelectBuilderInterface;

/**
* A decorator for a linked product select builder.
*
* Extends functionality of the linked product select builder to allow perform
* some additional processing of built Select objects.
*/
class LinkedProductSelectBuilder implements LinkedProductSelectBuilderInterface
{
/**
* @var BaseSelectProcessorInterface
*/
private $baseSelectProcessor;

/**
* @var LinkedProductSelectBuilderInterface
*/
private $linkedProductSelectBuilder;

/**
* @param BaseSelectProcessorInterface $baseSelectProcessor
* @param LinkedProductSelectBuilderInterface $linkedProductSelectBuilder
*/
public function __construct(
BaseSelectProcessorInterface $baseSelectProcessor,
LinkedProductSelectBuilderInterface $linkedProductSelectBuilder
) {
$this->baseSelectProcessor = $baseSelectProcessor;
$this->linkedProductSelectBuilder = $linkedProductSelectBuilder;
}

/**
* {@inheritdoc}
*/
public function build($productId)
{
$selects = $this->linkedProductSelectBuilder->build($productId);

foreach ($selects as $select) {
$this->baseSelectProcessor->process($select);
}

return $selects;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\ConfigurableProduct\Model\ResourceModel\Product;

use Magento\Framework\DB\Select;
use Magento\Catalog\Model\ResourceModel\Product\BaseSelectProcessorInterface;
use Magento\CatalogInventory\Api\StockConfigurationInterface;
use Magento\CatalogInventory\Model\Stock\Status as StockStatus;
use Magento\CatalogInventory\Model\ResourceModel\Stock\Status as StockStatusResource;

/**
* A Select object processor.
*
* Adds stock status limitations to a given Select object.
*/
class StockStatusBaseSelectProcessor implements BaseSelectProcessorInterface
{
/**
* @var StockConfigurationInterface
*/
private $stockConfig;

/**
* @var StockStatusResource
*/
private $stockStatusResource;

/**
* @param StockConfigurationInterface $stockConfig
* @param StockStatusResource $stockStatusResource
*/
public function __construct(
StockConfigurationInterface $stockConfig,
StockStatusResource $stockStatusResource
) {
$this->stockConfig = $stockConfig;
$this->stockStatusResource = $stockStatusResource;
}

/**
* {@inheritdoc}
*/
public function process(Select $select)
{
if ($this->stockConfig->isShowOutOfStock()) {
$select->joinInner(
['stock' => $this->stockStatusResource->getMainTable()],
sprintf(
'stock.product_id = %s.entity_id',
BaseSelectProcessorInterface::PRODUCT_TABLE_ALIAS
),
[]
)->where(
'stock.stock_status = ?',
StockStatus::STATUS_IN_STOCK
);
}

return $select;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\ConfigurableProduct\Plugin\Catalog\Model\Product\Pricing\Renderer;

use Magento\ConfigurableProduct\Pricing\Price\LowestPriceOptionsProviderInterface;

/**
* A plugin for a salable resolver.
*/
class SalableResolver
{
/**
* @var LowestPriceOptionsProviderInterface
*/
private $lowestPriceOptionsProvider;

/**
* @param LowestPriceOptionsProviderInterface $lowestPriceOptionsProvider
*/
public function __construct(
LowestPriceOptionsProviderInterface $lowestPriceOptionsProvider
) {
$this->lowestPriceOptionsProvider = $lowestPriceOptionsProvider;
}

/**
* Performs an additional check whether given configurable product has
* at least one configuration in-stock.
*
* @param \Magento\Catalog\Model\Product\Pricing\Renderer\SalableResolver $subject
* @param bool $result
* @param \Magento\Framework\Pricing\SaleableInterface $salableItem
*
* @return bool
*
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function afterIsSalable(
\Magento\Catalog\Model\Product\Pricing\Renderer\SalableResolver $subject,
$result,
\Magento\Framework\Pricing\SaleableInterface $salableItem
) {
if ($salableItem->getTypeId() == 'configurable' && $result) {
if (!$this->lowestPriceOptionsProvider->getProducts($salableItem)) {
$result = false;
}
}

return $result;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\ConfigurableProduct\Test\Unit\Model\ResourceModel\Product;

use Magento\Framework\DB\Select;
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
use Magento\Catalog\Model\ResourceModel\Product\BaseSelectProcessorInterface;
use Magento\Catalog\Model\ResourceModel\Product\LinkedProductSelectBuilderInterface;
use Magento\ConfigurableProduct\Model\ResourceModel\Product\LinkedProductSelectBuilder;

class LinkedProductSelectBuilderTest extends \PHPUnit\Framework\TestCase
{
/**
* @var LinkedProductSelectBuilder
*/
private $subject;

/**
* @var BaseSelectProcessorInterface|\PHPUnit_Framework_MockObject_MockObject
*/
private $baseSelectProcessorMock;

/**
* @var LinkedProductSelectBuilderInterface|\PHPUnit_Framework_MockObject_MockObject
*/
private $linkedProductSelectBuilderMock;

protected function setUp()
{
$this->baseSelectProcessorMock = $this->getMockBuilder(BaseSelectProcessorInterface::class)
->disableOriginalConstructor()
->getMockForAbstractClass();

$this->linkedProductSelectBuilderMock = $this->getMockBuilder(LinkedProductSelectBuilderInterface::class)
->disableOriginalConstructor()
->getMockForAbstractClass();

$this->subject = (new ObjectManager($this))->getObject(
LinkedProductSelectBuilder::class,
[
'baseSelectProcessor' => $this->baseSelectProcessorMock,
'linkedProductSelectBuilder' => $this->linkedProductSelectBuilderMock
]
);
}

public function testBuild()
{
$productId = 42;

/** @var Select|\PHPUnit_Framework_MockObject_MockObject $selectMock */
$selectMock = $this->getMockBuilder(Select::class)
->disableOriginalConstructor()
->getMock();

$expectedResult = [$selectMock];

$this->linkedProductSelectBuilderMock->expects($this->any())
->method('build')
->with($productId)
->willReturn($expectedResult);

$this->baseSelectProcessorMock->expects($this->once())
->method('process')
->with($selectMock);

$this->assertEquals($expectedResult, $this->subject->build($productId));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\ConfigurableProduct\Test\Unit\Model\ResourceModel\Product;

use Magento\Framework\DB\Select;
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
use Magento\Catalog\Model\ResourceModel\Product\BaseSelectProcessorInterface;
use Magento\CatalogInventory\Api\StockConfigurationInterface;
use Magento\CatalogInventory\Model\Stock\Status as StockStatus;
use Magento\CatalogInventory\Model\ResourceModel\Stock\Status as StockStatusResource;
use Magento\ConfigurableProduct\Model\ResourceModel\Product\StockStatusBaseSelectProcessor;

class StockStatusBaseSelectProcessorTest extends \PHPUnit\Framework\TestCase
{
/**
* @var StockStatusBaseSelectProcessor
*/
private $subject;

/**
* @var StockConfigurationInterface|\PHPUnit_Framework_MockObject_MockObject
*/
private $stockConfigMock;

/**
* @var string
*/
private $stockStatusTable = 'cataloginventory_stock_status';

/**
* @var StockStatusResource|\PHPUnit_Framework_MockObject_MockObject
*/
private $stockStatusResourceMock;

protected function setUp()
{
$this->stockConfigMock = $this->getMockBuilder(StockConfigurationInterface::class)
->disableOriginalConstructor()
->getMockForAbstractClass();

$this->stockStatusResourceMock = $this->getMockBuilder(StockStatusResource::class)
->disableOriginalConstructor()
->getMock();
$this->stockStatusResourceMock->expects($this->any())
->method('getMainTable')
->willReturn($this->stockStatusTable);

$this->subject = (new ObjectManager($this))->getObject(
StockStatusBaseSelectProcessor::class,
[
'stockConfig' => $this->stockConfigMock,
'stockStatusResource' => $this->stockStatusResourceMock
]
);
}

/**
* @param bool $isShowOutOfStock
*
* @dataProvider processDataProvider
*/
public function testProcess($isShowOutOfStock)
{
$this->stockConfigMock->expects($this->any())
->method('isShowOutOfStock')
->willReturn($isShowOutOfStock);

/** @var Select|\PHPUnit_Framework_MockObject_MockObject $selectMock */
$selectMock = $this->getMockBuilder(Select::class)
->disableOriginalConstructor()
->getMock();

if ($isShowOutOfStock) {
$selectMock->expects($this->once())
->method('joinInner')
->with(
['stock' => $this->stockStatusTable],
sprintf(
'stock.product_id = %s.entity_id',
BaseSelectProcessorInterface::PRODUCT_TABLE_ALIAS
),
[]
)
->willReturnSelf();
$selectMock->expects($this->once())
->method('where')
->with(
'stock.stock_status = ?',
StockStatus::STATUS_IN_STOCK
)
->willReturnSelf();
} else {
$selectMock->expects($this->never())
->method($this->anything());
}

$this->assertEquals($selectMock, $this->subject->process($selectMock));
}

/**
* @return array
*/
public function processDataProvider()
{
return [
'Out of stock products are being displayed' => [true],
'Out of stock products are NOT being displayed' => [false]
];
}
}
13 changes: 13 additions & 0 deletions app/code/Magento/ConfigurableProduct/etc/di.xml
Original file line number Diff line number Diff line change
Expand Up @@ -196,4 +196,17 @@
<argument name="productIndexer" xsi:type="object">Magento\Catalog\Model\Indexer\Product\Full</argument>
</arguments>
</type>
<type name="Magento\ConfigurableProduct\Pricing\Price\LowestPriceOptionsProvider">
<arguments>
<argument name="linkedProductSelectBuilder" xsi:type="object">Magento\ConfigurableProduct\Model\ResourceModel\Product\LinkedProductSelectBuilder</argument>
</arguments>
</type>
<type name="Magento\ConfigurableProduct\Model\ResourceModel\Product\LinkedProductSelectBuilder">
<arguments>
<argument name="baseSelectProcessor" xsi:type="object">Magento\ConfigurableProduct\Model\ResourceModel\Product\StockStatusBaseSelectProcessor</argument>
</arguments>
</type>
<type name="Magento\Catalog\Model\Product\Pricing\Renderer\SalableResolver">
<plugin name="configurable" type="Magento\ConfigurableProduct\Plugin\Catalog\Model\Product\Pricing\Renderer\SalableResolver" />
</type>
</config>
Original file line number Diff line number Diff line change
Expand Up @@ -1096,7 +1096,7 @@
<item name="is_in_stock" xsi:type="string">Out of Stock</item>
</field>
<field name="price" xsi:type="array">
<item name="value" xsi:type="string">560</item>
<item name="value" xsi:type="string">561</item>
</field>
<field name="tax_class_id" xsi:type="array">
<item name="dataset" xsi:type="string">taxable_goods</item>
Expand Down
Loading

0 comments on commit dfd934f

Please sign in to comment.