diff --git a/app/code/Magento/Bundle/Model/ResourceModel/Selection.php b/app/code/Magento/Bundle/Model/ResourceModel/Selection.php index 5fbaea72417b03dd5195a6c81a130454203408d4..b67f9c0f3143fd19fb2752e9be4618b9bc622ba0 100644 --- a/app/code/Magento/Bundle/Model/ResourceModel/Selection.php +++ b/app/code/Magento/Bundle/Model/ResourceModel/Selection.php @@ -120,10 +120,11 @@ class Selection extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb true )->from( $this->getMainTable(), - 'parent_product_id' + '' )->join( ['e' => $this->metadataPool->getMetadata(ProductInterface::class)->getEntityTable()], - 'e.' . $metadata->getLinkField() . ' = ' . $this->getMainTable() . '.parent_product_id' + 'e.' . $metadata->getLinkField() . ' = ' . $this->getMainTable() . '.parent_product_id', + ['e.entity_id as parent_product_id'] )->where( 'e.entity_id IN(?)', $childId diff --git a/app/code/Magento/Bundle/Test/Unit/Model/LinkManagementTest.php b/app/code/Magento/Bundle/Test/Unit/Model/LinkManagementTest.php index 42e751491860f8f20f54eb7026d5db5fb59d89d1..6bc4c9d5f212c93f1a0235d1ebf91ad505af677c 100644 --- a/app/code/Magento/Bundle/Test/Unit/Model/LinkManagementTest.php +++ b/app/code/Magento/Bundle/Test/Unit/Model/LinkManagementTest.php @@ -98,6 +98,21 @@ class LinkManagementTest extends \PHPUnit_Framework_TestCase */ protected $dataObjectHelperMock; + /** + * @var \Magento\Framework\Model\Entity\MetadataPool|\PHPUnit_Framework_MockObject_MockObject + */ + protected $metadataPoolMock; + + /** + * @var \Magento\Framework\Model\Entity\EntityMetadata|\PHPUnit_Framework_MockObject_MockObject + */ + protected $metadataMock; + + /** + * @var string + */ + protected $linkField = 'product_id'; + protected function setUp() { $helper = new ObjectManager($this); @@ -122,7 +137,7 @@ class LinkManagementTest extends \PHPUnit_Framework_TestCase ->disableOriginalConstructor() ->getMock(); $this->product = $this->getMockBuilder('Magento\Catalog\Model\Product') - ->setMethods(['getTypeInstance', 'getStoreId', 'getTypeId', '__wakeup', 'getId']) + ->setMethods(['getTypeInstance', 'getStoreId', 'getTypeId', '__wakeup', 'getId', 'getData']) ->disableOriginalConstructor() ->getMock(); $this->link = $this->getMockBuilder('\Magento\Bundle\Api\Data\LinkInterface') @@ -142,6 +157,15 @@ class LinkManagementTest extends \PHPUnit_Framework_TestCase '\Magento\Bundle\Model\ResourceModel\Option\CollectionFactory', ['create'], [], '', false ); $this->storeManagerMock = $this->getMock('\Magento\Store\Model\StoreManagerInterface', [], [], '', false); + $this->metadataPoolMock = $this->getMockBuilder('\Magento\Framework\Model\Entity\MetadataPool') + ->disableOriginalConstructor() + ->getMock(); + $this->metadataMock = $this->getMockBuilder('\Magento\Framework\Model\Entity\EntityMetadata') + ->disableOriginalConstructor() + ->getMock(); + $this->metadataPoolMock->expects($this->any())->method('getMetadata') + ->with(\Magento\Catalog\Api\Data\ProductInterface::class) + ->willReturn($this->metadataMock); $this->dataObjectHelperMock = $this->getMockBuilder('\Magento\Framework\Api\DataObjectHelper') ->disableOriginalConstructor() @@ -156,6 +180,7 @@ class LinkManagementTest extends \PHPUnit_Framework_TestCase 'optionCollection' => $this->optionCollectionFactoryMock, 'storeManager' => $this->storeManagerMock, 'dataObjectHelper' => $this->dataObjectHelperMock, + 'metadataPool' => $this->metadataPoolMock ] ); } @@ -185,7 +210,8 @@ class LinkManagementTest extends \PHPUnit_Framework_TestCase ->with($this->equalTo($this->selectionCollection)) ->will($this->returnValue([$this->option])); - $this->option->expects($this->any())->method('getSelections')->will($this->returnValue([$this->product])); + $this->option->expects($this->any())->method('getSelections')->willReturn([$this->product]); + $this->product->expects($this->any())->method('getData')->willReturn([]); $this->dataObjectHelperMock->expects($this->once()) ->method('populateWithArray') @@ -316,11 +342,15 @@ class LinkManagementTest extends \PHPUnit_Framework_TestCase $productLink->expects($this->any())->method('getSku')->will($this->returnValue('linked_product_sku')); $productLink->expects($this->any())->method('getOptionId')->will($this->returnValue(1)); + $this->metadataMock->expects($this->once())->method('getLinkField')->willReturn($this->linkField); $productMock = $this->getMock('\Magento\Catalog\Model\Product', [], [], '', false); $productMock->expects($this->once())->method('getTypeId')->will($this->returnValue( \Magento\Catalog\Model\Product\Type::TYPE_BUNDLE )); - $productMock->expects($this->any())->method('getId')->will($this->returnValue('product_id')); + $productMock->expects($this->any()) + ->method('getData') + ->with($this->linkField) + ->willReturn($this->linkField); $linkedProductMock = $this->getMock('\Magento\Catalog\Model\Product', [], [], '', false); $linkedProductMock->expects($this->any())->method('getId')->will($this->returnValue(13)); @@ -340,7 +370,13 @@ class LinkManagementTest extends \PHPUnit_Framework_TestCase ->getMock(); $option->expects($this->once())->method('getId')->will($this->returnValue(1)); - $optionsCollectionMock = $this->getMock('\Magento\Bundle\Model\ResourceModel\Option\Collection', [], [], '', false); + $optionsCollectionMock = $this->getMock( + '\Magento\Bundle\Model\ResourceModel\Option\Collection', + [], + [], + '', + false + ); $optionsCollectionMock->expects($this->once()) ->method('setIdFilter') ->with($this->equalTo('1')) @@ -353,7 +389,7 @@ class LinkManagementTest extends \PHPUnit_Framework_TestCase ); $bundle = $this->getMock('\Magento\Bundle\Model\ResourceModel\Bundle', [], [], '', false); - $bundle->expects($this->once())->method('getSelectionsData')->with('product_id')->will($this->returnValue([])); + $bundle->expects($this->once())->method('getSelectionsData')->with($this->linkField)->willReturn([]); $this->bundleFactoryMock->expects($this->once())->method('create')->will($this->returnValue($bundle)); $this->model->addChild($productMock, 1, $productLink); } @@ -367,11 +403,15 @@ class LinkManagementTest extends \PHPUnit_Framework_TestCase $productLink->expects($this->any())->method('getSku')->will($this->returnValue('linked_product_sku')); $productLink->expects($this->any())->method('getOptionId')->will($this->returnValue(1)); + $this->metadataMock->expects($this->once())->method('getLinkField')->willReturn($this->linkField); $productMock = $this->getMock('\Magento\Catalog\Model\Product', [], [], '', false); $productMock->expects($this->once())->method('getTypeId')->will($this->returnValue( \Magento\Catalog\Model\Product\Type::TYPE_BUNDLE )); - $productMock->expects($this->any())->method('getId')->will($this->returnValue('product_id')); + $productMock->expects($this->any()) + ->method('getData') + ->with($this->linkField) + ->willReturn($this->linkField); $linkedProductMock = $this->getMock('\Magento\Catalog\Model\Product', [], [], '', false); $linkedProductMock->expects($this->any())->method('getEntityId')->will($this->returnValue(13)); @@ -391,7 +431,13 @@ class LinkManagementTest extends \PHPUnit_Framework_TestCase ->getMock(); $option->expects($this->once())->method('getId')->will($this->returnValue(1)); - $optionsCollectionMock = $this->getMock('\Magento\Bundle\Model\ResourceModel\Option\Collection', [], [], '', false); + $optionsCollectionMock = $this->getMock( + '\Magento\Bundle\Model\ResourceModel\Option\Collection', + [], + [], + '', + false + ); $optionsCollectionMock->expects($this->once()) ->method('setIdFilter') ->with($this->equalTo(1)) @@ -409,7 +455,7 @@ class LinkManagementTest extends \PHPUnit_Framework_TestCase ]; $bundle = $this->getMock('\Magento\Bundle\Model\ResourceModel\Bundle', [], [], '', false); $bundle->expects($this->once())->method('getSelectionsData') - ->with('product_id') + ->with($this->linkField) ->will($this->returnValue($selections)); $this->bundleFactoryMock->expects($this->once())->method('create')->will($this->returnValue($bundle)); $this->model->addChild($productMock, 1, $productLink); @@ -424,11 +470,16 @@ class LinkManagementTest extends \PHPUnit_Framework_TestCase $productLink->expects($this->any())->method('getSku')->will($this->returnValue('linked_product_sku')); $productLink->expects($this->any())->method('getOptionId')->will($this->returnValue(1)); + $this->metadataMock->expects($this->once())->method('getLinkField')->willReturn($this->linkField); $productMock = $this->getMock('\Magento\Catalog\Model\Product', [], [], '', false); $productMock->expects($this->once())->method('getTypeId')->will($this->returnValue( \Magento\Catalog\Model\Product\Type::TYPE_BUNDLE )); - $productMock->expects($this->any())->method('getId')->will($this->returnValue('product_id')); + $productMock->expects($this->any()) + ->method('getData') + ->with($this->linkField) + ->willReturn($this->linkField); + $linkedProductMock = $this->getMock('\Magento\Catalog\Model\Product', [], [], '', false); $linkedProductMock->expects($this->any())->method('getId')->will($this->returnValue(13)); @@ -468,7 +519,7 @@ class LinkManagementTest extends \PHPUnit_Framework_TestCase ]; $bundle = $this->getMock('\Magento\Bundle\Model\ResourceModel\Bundle', [], [], '', false); $bundle->expects($this->once())->method('getSelectionsData') - ->with('product_id') + ->with($this->linkField) ->will($this->returnValue($selections)); $this->bundleFactoryMock->expects($this->once())->method('create')->will($this->returnValue($bundle)); @@ -491,11 +542,15 @@ class LinkManagementTest extends \PHPUnit_Framework_TestCase $productLink->expects($this->any())->method('getSku')->will($this->returnValue('linked_product_sku')); $productLink->expects($this->any())->method('getOptionId')->will($this->returnValue(1)); + $this->metadataMock->expects($this->once())->method('getLinkField')->willReturn($this->linkField); $productMock = $this->getMock('\Magento\Catalog\Model\Product', [], [], '', false); $productMock->expects($this->once())->method('getTypeId')->will($this->returnValue( \Magento\Catalog\Model\Product\Type::TYPE_BUNDLE )); - $productMock->expects($this->any())->method('getId')->will($this->returnValue('product_id')); + $productMock->expects($this->any()) + ->method('getData') + ->with($this->linkField) + ->willReturn($this->linkField); $linkedProductMock = $this->getMock('\Magento\Catalog\Model\Product', [], [], '', false); $linkedProductMock->expects($this->any())->method('getId')->will($this->returnValue(13)); @@ -535,7 +590,7 @@ class LinkManagementTest extends \PHPUnit_Framework_TestCase ]; $bundle = $this->getMock('\Magento\Bundle\Model\ResourceModel\Bundle', [], [], '', false); $bundle->expects($this->once())->method('getSelectionsData') - ->with('product_id') + ->with($this->linkField) ->will($this->returnValue($selections)); $this->bundleFactoryMock->expects($this->once())->method('create')->will($this->returnValue($bundle)); @@ -572,11 +627,15 @@ class LinkManagementTest extends \PHPUnit_Framework_TestCase $productLink->expects($this->any())->method('getCanChangeQuantity')->will($this->returnValue($canChangeQuantity)); $productLink->expects($this->any())->method('getIsDefault')->will($this->returnValue($isDefault)); + $this->metadataMock->expects($this->once())->method('getLinkField')->willReturn($this->linkField); $productMock = $this->getMock('\Magento\Catalog\Model\Product', [], [], '', false); $productMock->expects($this->once())->method('getTypeId')->will($this->returnValue( \Magento\Catalog\Model\Product\Type::TYPE_BUNDLE )); - $productMock->expects($this->any())->method('getEntityId')->will($this->returnValue($parentProductId)); + $productMock->expects($this->any()) + ->method('getData') + ->with($this->linkField) + ->willReturn($parentProductId); $linkedProductMock = $this->getMock('\Magento\Catalog\Model\Product', [], [], '', false); $linkedProductMock->expects($this->any())->method('getId')->will($this->returnValue($linkProductId)); @@ -866,7 +925,11 @@ class LinkManagementTest extends \PHPUnit_Framework_TestCase $selection->expects($this->any())->method('getProductId')->willReturn($productId); $this->option->expects($this->any())->method('getSelections')->will($this->returnValue([$selection])); - $this->product->expects($this->any())->method('getId')->will($this->returnValue(3)); + $this->metadataMock->expects($this->any())->method('getLinkField')->willReturn($this->linkField); + $this->product->expects($this->any()) + ->method('getData') + ->with($this->linkField) + ->willReturn(3); $bundle->expects($this->once())->method('dropAllUnneededSelections')->with(3, []); $bundle->expects($this->once())->method('removeProductRelations')->with(3, [$productId]); diff --git a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Initialization/HelperTest.php b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Initialization/HelperTest.php index 828cc31c1725cec790e89707948859e69c15d25a..e64d8c2ef84fa9c3d777eacbaaebfebf4ee00e60 100644 --- a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Initialization/HelperTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Initialization/HelperTest.php @@ -359,13 +359,8 @@ class HelperTest extends \PHPUnit_Framework_TestCase { $linkMock = $this->getMockBuilder(ProductLinkInterface::class) ->disableOriginalConstructor() - ->setMethods(['getLinkType']) ->getMockForAbstractClass(); - $linkMock->expects($this->once()) - ->method('getLinkType') - ->willReturn('upsell'); - $this->productMock->expects($this->any()) ->method('getProductLinks') ->willReturn([$linkMock]); diff --git a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/category/checkboxes/tree.phtml b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/category/checkboxes/tree.phtml index 25aaaea0ffe2b98a6e46a7e133c53b743603530e..284f241b3ba54f834f2d5057bf1a67458645aa03 100644 --- a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/category/checkboxes/tree.phtml +++ b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/category/checkboxes/tree.phtml @@ -10,7 +10,7 @@ <?php $_divId = 'tree-div_' . time() ?> <div id="<?php /* @escapeNotVerified */ echo $_divId ?>" class="tree"></div> -<script id="ie-deferred-loader" defer="defer" src=""></script> +<script id="ie-deferred-loader" defer="defer" src="//:"></script> <script> require([ 'jquery', diff --git a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/category/widget/tree.phtml b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/category/widget/tree.phtml index 9e303fe921dfd328453c0f736a107fa4be70e6fa..ae65d2658978a3f2e74dc04278ce9d803dda471a 100644 --- a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/category/widget/tree.phtml +++ b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/category/widget/tree.phtml @@ -11,7 +11,7 @@ <?php $_divId = 'tree' . $block->getId() ?> <div id="<?php /* @escapeNotVerified */ echo $_divId ?>" class="tree"></div> <!--[if IE]> -<script id="ie-deferred-loader" defer="defer" src=""></script> +<script id="ie-deferred-loader" defer="defer" src="//:"></script> <![endif]--> <script> require(['jquery', "prototype", "extjs/ext-tree-checkbox"], function(jQuery){ diff --git a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/attribute/set/main.phtml b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/attribute/set/main.phtml index f1bba6cc3c07ca0603e149afc8f0ad24b342a467..b3a7002ef417ecb3cc14006aa34b6844a32d8a67 100644 --- a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/attribute/set/main.phtml +++ b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/attribute/set/main.phtml @@ -38,7 +38,7 @@ <span class="title"><?php /* @escapeNotVerified */ echo __('Unassigned Attributes') ?></span> </div> <div id="tree-div2" class="attribute-set-tree"></div> - <script id="ie-deferred-loader" defer="defer" src=""></script> + <script id="ie-deferred-loader" defer="defer" src="//:"></script> <script> define("tree-panel", [ diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product.php b/app/code/Magento/CatalogImportExport/Model/Import/Product.php index be5131c2b3bdceb099cb84455ac2b1c7562c0752..415ec8bd0072491aef33fecc72f85cd2640b221e 100644 --- a/app/code/Magento/CatalogImportExport/Model/Import/Product.php +++ b/app/code/Magento/CatalogImportExport/Model/Import/Product.php @@ -1162,7 +1162,7 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity foreach ($skuData as $sku => $attributes) { $linkId = $this->_connection->fetchOne( $this->_connection->select() - ->from($this->_resource->getTable('catalog_product_entity')) + ->from($this->getResource()->getTable('catalog_product_entity')) ->where('sku = ?', $sku) ->columns($metadata->getLinkField()) ); @@ -1971,7 +1971,7 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity $productIdsToReindex[] = $row['product_id']; $row['website_id'] = $this->stockConfiguration->getDefaultScopeId(); - $row['stock_id'] = $this->stockRegistry->getStock()->getStockId(); + $row['stock_id'] = $this->stockRegistry->getStock($row['website_id'])->getStockId(); $stockItemDo = $this->stockRegistry->getStockItem($row['product_id'], $row['website_id']); $existStockData = $stockItemDo->getData(); diff --git a/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/ProductTest.php b/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/ProductTest.php index fd2d6e9fb4646e67cb7e688253fed3178812d417..ae443adc9b5872ed9d41704cdc08c807ab5f3e8f 100644 --- a/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/ProductTest.php +++ b/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/ProductTest.php @@ -527,10 +527,28 @@ class ProductTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractI ] ] ]; - $this->skuProcessor->expects($this->once()) - ->method('getNewSku') - ->with($testSku) - ->willReturn(['entity_id' => self::ENTITY_ID]); + $metadataMock = $this->getMockBuilder('\Magento\Framework\Model\Entity\EntityMetadata') + ->disableOriginalConstructor() + ->getMock(); + $this->metadataPool->expects($this->any())->method('getMetadata') + ->with(\Magento\Catalog\Api\Data\ProductInterface::class) + ->willReturn($metadataMock); + $metadataMock->expects($this->any())->method('getLinkField')->willReturn('entity_id'); + $entityTable = 'catalog_product_entity'; + $resource = $this->getMockBuilder('\Magento\CatalogImportExport\Model\Import\Proxy\Product\ResourceModel') + ->disableOriginalConstructor() + ->setMethods(['getTable']) + ->getMock(); + $resource->expects($this->once())->method('getTable')->with($entityTable)->willReturnArgument(0); + $this->_resourceFactory->expects($this->once())->method('create')->willReturn($resource); + $selectMock = $this->getMockBuilder('Magento\Framework\DB\Select') + ->disableOriginalConstructor() + ->getMock(); + $selectMock->expects($this->once())->method('from')->with($entityTable, '*', null)->willReturnSelf(); + $selectMock->expects($this->once())->method('where')->with('sku = ?', $testSku)->willReturnSelf(); + $selectMock->expects($this->once())->method('columns')->with('entity_id')->willReturnSelf(); + $this->_connection->expects($this->any())->method('fetchOne')->willReturn(self::ENTITY_ID); + $this->_connection->expects($this->any())->method('select')->willReturn($selectMock); $this->_connection->expects($this->any()) ->method('quoteInto') ->willReturnCallback([$this, 'returnQuoteCallback']); diff --git a/app/code/Magento/CatalogInventory/Api/StockRegistryInterface.php b/app/code/Magento/CatalogInventory/Api/StockRegistryInterface.php index 27b45dc6771632f08a2f8aa62619d6324bcf7d02..2566aff49b0dc9cea7412906f8096ea9df7d48f6 100644 --- a/app/code/Magento/CatalogInventory/Api/StockRegistryInterface.php +++ b/app/code/Magento/CatalogInventory/Api/StockRegistryInterface.php @@ -12,10 +12,10 @@ namespace Magento\CatalogInventory\Api; interface StockRegistryInterface { /** - * @param int|null $stockId + * @param int $scopeId * @return \Magento\CatalogInventory\Api\Data\StockInterface */ - public function getStock($stockId = null); + public function getStock($scopeId = null); /** * @param int $productId diff --git a/app/code/Magento/CatalogInventory/Api/StockStatusCriteriaInterface.php b/app/code/Magento/CatalogInventory/Api/StockStatusCriteriaInterface.php index 44d3c1be11fab1f18b79bb0cf269198688c54eee..bb3d101e97f9f830c81941e0cfc0670e79ad6f49 100644 --- a/app/code/Magento/CatalogInventory/Api/StockStatusCriteriaInterface.php +++ b/app/code/Magento/CatalogInventory/Api/StockStatusCriteriaInterface.php @@ -15,7 +15,7 @@ interface StockStatusCriteriaInterface extends \Magento\Framework\Api\CriteriaIn * Add Criteria object * * @param \Magento\CatalogInventory\Api\StockStatusCriteriaInterface $criteria - * @return void + * @return bool */ public function addCriteria(\Magento\CatalogInventory\Api\StockStatusCriteriaInterface $criteria); @@ -23,7 +23,7 @@ interface StockStatusCriteriaInterface extends \Magento\Framework\Api\CriteriaIn * Filter by scope(s) * * @param int $scope - * @return void + * @return bool */ public function setScopeFilter($scope); @@ -31,7 +31,7 @@ interface StockStatusCriteriaInterface extends \Magento\Framework\Api\CriteriaIn * Add product(s) filter * * @param int $products - * @return void + * @return bool */ public function setProductsFilter($products); @@ -39,7 +39,7 @@ interface StockStatusCriteriaInterface extends \Magento\Framework\Api\CriteriaIn * Add filter by quantity * * @param float $qty - * @return void + * @return bool */ public function setQtyFilter($qty); } diff --git a/app/code/Magento/CatalogInventory/Helper/Stock.php b/app/code/Magento/CatalogInventory/Helper/Stock.php index 4706a60bf5250a18f4ebcfb7dd10efc9cf3fe8ed..8a227f53ebc1fce93a93a809ab5a0c1e887c06c4 100644 --- a/app/code/Magento/CatalogInventory/Helper/Stock.php +++ b/app/code/Magento/CatalogInventory/Helper/Stock.php @@ -6,7 +6,6 @@ namespace Magento\CatalogInventory\Helper; use Magento\CatalogInventory\Model\Spi\StockRegistryProviderInterface; -use Magento\CatalogInventory\Model\Spi\StockResolverInterface; use Magento\Store\Model\StoreManagerInterface; use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\CatalogInventory\Model\ResourceModel\Stock\StatusFactory; @@ -48,45 +47,36 @@ class Stock */ private $stockRegistryProvider; - /** - * @var StockResolverInterface - */ - protected $stockResolver; - /** * @param StoreManagerInterface $storeManager * @param ScopeConfigInterface $scopeConfig * @param StatusFactory $stockStatusFactory * @param StockRegistryProviderInterface $stockRegistryProvider - * @param StockResolverInterface $stockResolver */ public function __construct( StoreManagerInterface $storeManager, ScopeConfigInterface $scopeConfig, StatusFactory $stockStatusFactory, - StockRegistryProviderInterface $stockRegistryProvider, - StockResolverInterface $stockResolver + StockRegistryProviderInterface $stockRegistryProvider ) { $this->storeManager = $storeManager; $this->scopeConfig = $scopeConfig; $this->stockStatusFactory = $stockStatusFactory; $this->stockRegistryProvider = $stockRegistryProvider; - $this->stockResolver = $stockResolver; } /** * Assign stock status information to product * * @param Product $product - * @param int $stockStatus + * @param int $status * @return void */ - public function assignStatusToProduct(Product $product, $stockStatus = null) + public function assignStatusToProduct(Product $product, $status = null) { - if ($stockStatus === null) { - $productId = $product->getId(); - $stockId = $this->stockResolver->getStockId($productId, $product->getStore()->getWebsiteId()); - $stockStatus = $this->stockRegistryProvider->getStockStatus($productId, $stockId); + if ($status === null) { + $websiteId = $product->getStore()->getWebsiteId(); + $stockStatus = $this->stockRegistryProvider->getStockStatus($product->getId(), $websiteId); $status = $stockStatus->getStockStatus(); } $product->setIsSalable($status); @@ -103,8 +93,7 @@ class Stock $websiteId = $this->storeManager->getStore($productCollection->getStoreId())->getWebsiteId(); foreach ($productCollection as $product) { $productId = $product->getId(); - $stockId = $this->stockResolver->getStockId($productId, $websiteId); - $stockStatus = $this->stockRegistryProvider->getStockStatus($productId, $stockId); + $stockStatus = $this->stockRegistryProvider->getStockStatus($productId, $websiteId); $status = $stockStatus->getStockStatus(); $product->setIsSalable($status); } diff --git a/app/code/Magento/CatalogInventory/Model/Spi/StockRegistryProviderInterface.php b/app/code/Magento/CatalogInventory/Model/Spi/StockRegistryProviderInterface.php index a08aa33533301bd12c4c285da368de9a9a4492ec..8fb68a2c997be868f117803c18c292f74f2e4076 100644 --- a/app/code/Magento/CatalogInventory/Model/Spi/StockRegistryProviderInterface.php +++ b/app/code/Magento/CatalogInventory/Model/Spi/StockRegistryProviderInterface.php @@ -11,22 +11,22 @@ namespace Magento\CatalogInventory\Model\Spi; interface StockRegistryProviderInterface { /** - * @param int|null $stockId + * @param int $scopeId * @return \Magento\CatalogInventory\Api\Data\StockInterface */ - public function getStock($stockId); + public function getStock($scopeId); /** * @param int $productId - * @param int $stockId + * @param int $scopeId * @return \Magento\CatalogInventory\Api\Data\StockItemInterface */ - public function getStockItem($productId, $stockId); + public function getStockItem($productId, $scopeId); /** * @param int $productId - * @param int $stockId + * @param int $scopeId * @return \Magento\CatalogInventory\Api\Data\StockStatusInterface */ - public function getStockStatus($productId, $stockId); + public function getStockStatus($productId, $scopeId); } diff --git a/app/code/Magento/CatalogInventory/Model/Spi/StockResolverInterface.php b/app/code/Magento/CatalogInventory/Model/Spi/StockResolverInterface.php deleted file mode 100644 index b4f9df8f079da74b7d5ad09a0ccdd675fbcc8978..0000000000000000000000000000000000000000 --- a/app/code/Magento/CatalogInventory/Model/Spi/StockResolverInterface.php +++ /dev/null @@ -1,19 +0,0 @@ -<?php -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\CatalogInventory\Model\Spi; - -/** - * Interface StockResolverInterface - */ -interface StockResolverInterface -{ - /** - * @param int $productId - * @param int $websiteId - * @return int - */ - public function getStockId($productId, $websiteId); -} diff --git a/app/code/Magento/CatalogInventory/Model/Stock/Item.php b/app/code/Magento/CatalogInventory/Model/Stock/Item.php index b97977fd3c013e006c53232b490aedd7f7f857cc..3c4c7bfdf143f7ff892af8d03207e07c8dd90f06 100644 --- a/app/code/Magento/CatalogInventory/Model/Stock/Item.php +++ b/app/code/Magento/CatalogInventory/Model/Stock/Item.php @@ -177,7 +177,7 @@ class Item extends AbstractExtensibleModel implements StockItemInterface { $stockId = $this->getData(static::STOCK_ID); if ($stockId === null) { - $stockId = $this->stockRegistry->getStock()->getStockId(); + $stockId = $this->stockRegistry->getStock($this->getWebsiteId())->getStockId(); } return (int) $stockId; } diff --git a/app/code/Magento/CatalogInventory/Model/StockIndex.php b/app/code/Magento/CatalogInventory/Model/StockIndex.php index d961f52ff519f1eaf604207deb5e6bc287396565..4c6f6521c97949980222f9ff310f418a13ba247f 100644 --- a/app/code/Magento/CatalogInventory/Model/StockIndex.php +++ b/app/code/Magento/CatalogInventory/Model/StockIndex.php @@ -13,7 +13,6 @@ use Magento\Catalog\Model\Product\Website as ProductWebsite; use Magento\Catalog\Model\ProductFactory; use Magento\CatalogInventory\Api\StockIndexInterface; use Magento\CatalogInventory\Model\Spi\StockRegistryProviderInterface; -use Magento\CatalogInventory\Model\Spi\StockResolverInterface; use Magento\Catalog\Api\ProductRepositoryInterface; /** @@ -56,31 +55,22 @@ class StockIndex implements StockIndexInterface */ protected $productTypes = []; - - /** - * @var StockResolverInterface - */ - protected $stockResolver; - /** * @param StockRegistryProviderInterface $stockRegistryProvider * @param ProductRepositoryInterface $productRepository * @param ProductWebsite $productWebsite * @param ProductType $productType - * @param StockResolverInterface $stockResolver */ public function __construct( StockRegistryProviderInterface $stockRegistryProvider, ProductRepositoryInterface $productRepository, ProductWebsite $productWebsite, - ProductType $productType, - StockResolverInterface $stockResolver + ProductType $productType ) { $this->stockRegistryProvider = $stockRegistryProvider; $this->productRepository = $productRepository; $this->productWebsite = $productWebsite; $this->productType = $productType; - $this->stockResolver = $stockResolver; } /** @@ -122,8 +112,7 @@ class StockIndex implements StockIndexInterface */ public function updateProductStockStatus($productId, $websiteId) { - $stockId = $this->stockResolver->getStockId($productId, $websiteId); - $item = $this->stockRegistryProvider->getStockItem($productId, $stockId); + $item = $this->stockRegistryProvider->getStockItem($productId, $websiteId); $status = \Magento\CatalogInventory\Model\Stock\Status::STATUS_IN_STOCK; $qty = 0; @@ -242,8 +231,7 @@ class StockIndex implements StockIndexInterface } foreach ($parentIds as $parentId) { - $stockId = $this->stockResolver->getStockId($productId, $websiteId); - $item = $this->stockRegistryProvider->getStockItem($parentId, $stockId); + $item = $this->stockRegistryProvider->getStockItem($parentId, $websiteId); $status = \Magento\CatalogInventory\Model\Stock\Status::STATUS_IN_STOCK; $qty = 0; if ($item->getItemId()) { diff --git a/app/code/Magento/CatalogInventory/Model/StockManagement.php b/app/code/Magento/CatalogInventory/Model/StockManagement.php index 7b08d2a757ebcdd98eed33dd94e87d0b1496eb97..9415c464c18c1e4b9a0bb0a41d3e1cc587b0bfed 100644 --- a/app/code/Magento/CatalogInventory/Model/StockManagement.php +++ b/app/code/Magento/CatalogInventory/Model/StockManagement.php @@ -10,7 +10,6 @@ use Magento\CatalogInventory\Api\StockConfigurationInterface; use Magento\CatalogInventory\Api\StockManagementInterface; use Magento\CatalogInventory\Model\ResourceModel\QtyCounterInterface; use Magento\CatalogInventory\Model\Spi\StockRegistryProviderInterface; -use Magento\CatalogInventory\Model\Spi\StockResolverInterface; use Magento\Catalog\Api\ProductRepositoryInterface; use Magento\CatalogInventory\Model\ResourceModel\Stock as ResourceStock; @@ -49,11 +48,6 @@ class StockManagement implements StockManagementInterface */ private $qtyCounter; - /** - * @var StockResolverInterface - */ - protected $stockResolver; - /** * @param ResourceStock $stockResource * @param StockRegistryProviderInterface $stockRegistryProvider @@ -61,7 +55,6 @@ class StockManagement implements StockManagementInterface * @param StockConfigurationInterface $stockConfiguration * @param ProductRepositoryInterface $productRepository * @param QtyCounterInterface $qtyCounter - * @param StockResolverInterface $stockResolver */ public function __construct( ResourceStock $stockResource, @@ -69,8 +62,7 @@ class StockManagement implements StockManagementInterface StockState $stockState, StockConfigurationInterface $stockConfiguration, ProductRepositoryInterface $productRepository, - QtyCounterInterface $qtyCounter, - StockResolverInterface $stockResolver + QtyCounterInterface $qtyCounter ) { $this->stockRegistryProvider = $stockRegistryProvider; $this->stockState = $stockState; @@ -78,7 +70,6 @@ class StockManagement implements StockManagementInterface $this->productRepository = $productRepository; $this->qtyCounter = $qtyCounter; $this->resource = $stockResource; - $this->stockResolver = $stockResolver; } /** @@ -93,9 +84,9 @@ class StockManagement implements StockManagementInterface */ public function registerProductsSale($items, $websiteId = null) { - if (!$websiteId) { - $websiteId = $this->stockConfiguration->getDefaultScopeId(); - } + //if (!$websiteId) { + $websiteId = $this->stockConfiguration->getDefaultScopeId(); + //} $this->getResource()->beginTransaction(); $lockedItems = $this->getResource()->lockProductsStock(array_keys($items), $websiteId); $fullSaveItems = $registeredItems = []; @@ -103,8 +94,7 @@ class StockManagement implements StockManagementInterface $productId = $lockedItemRecord['product_id']; /** @var StockItemInterface $stockItem */ $orderedQty = $items[$productId]; - $stockId = $this->stockResolver->getStockId($productId, $websiteId); - $stockItem = $this->stockRegistryProvider->getStockItem($productId, $stockId); + $stockItem = $this->stockRegistryProvider->getStockItem($productId, $websiteId); $canSubtractQty = $stockItem->getItemId() && $this->canSubtractQty($stockItem); if (!$canSubtractQty || !$this->stockConfiguration->isQty($lockedItemRecord['type_id'])) { continue; @@ -142,9 +132,9 @@ class StockManagement implements StockManagementInterface */ public function revertProductsSale($items, $websiteId = null) { - if (!$websiteId) { - $websiteId = $this->stockConfiguration->getDefaultScopeId(); - } + //if (!$websiteId) { + $websiteId = $this->stockConfiguration->getDefaultScopeId(); + //} $this->qtyCounter->correctItemsQty($items, $websiteId, '+'); return true; } @@ -159,11 +149,10 @@ class StockManagement implements StockManagementInterface */ public function backItemQty($productId, $qty, $scopeId = null) { - if (!$scopeId) { - $scopeId = $this->stockConfiguration->getDefaultScopeId(); - } - $stockId = $this->stockResolver->getStockId($productId, $scopeId); - $stockItem = $this->stockRegistryProvider->getStockItem($productId, $stockId); + //if (!$scopeId) { + $scopeId = $this->stockConfiguration->getDefaultScopeId(); + //} + $stockItem = $this->stockRegistryProvider->getStockItem($productId, $scopeId); if ($stockItem->getItemId() && $this->stockConfiguration->isQty($this->getProductType($productId))) { if ($this->canSubtractQty($stockItem)) { $stockItem->setQty($stockItem->getQty() + $qty); diff --git a/app/code/Magento/CatalogInventory/Model/StockRegistry.php b/app/code/Magento/CatalogInventory/Model/StockRegistry.php index d72719fdb3a0501e274a9d9d5b3990c072e5e3c0..fda30523c39ab445b8588ed5f65d0ea40e2e4e8f 100644 --- a/app/code/Magento/CatalogInventory/Model/StockRegistry.php +++ b/app/code/Magento/CatalogInventory/Model/StockRegistry.php @@ -11,9 +11,7 @@ use Magento\CatalogInventory\Api\StockConfigurationInterface; use Magento\CatalogInventory\Api\StockItemCriteriaInterfaceFactory; use Magento\CatalogInventory\Api\StockItemRepositoryInterface; use Magento\CatalogInventory\Api\StockRegistryInterface; -use Magento\CatalogInventory\Model\Spi\StockResolverInterface; use Magento\CatalogInventory\Model\Spi\StockRegistryProviderInterface; -use Magento\CatalogInventory\Model\Spi\StockStateProviderInterface; /** * Class StockRegistry @@ -47,49 +45,37 @@ class StockRegistry implements StockRegistryInterface */ protected $criteriaFactory; - /** - * @var \Magento\CatalogInventory\Model\Spi\StockResolverInterface - */ - protected $stockResolver; - - /** - * @var StockStateProviderInterface - */ - protected $stockStateProvider; - /** * @param StockConfigurationInterface $stockConfiguration * @param StockRegistryProviderInterface $stockRegistryProvider * @param StockItemRepositoryInterface $stockItemRepository * @param StockItemCriteriaInterfaceFactory $criteriaFactory * @param ProductFactory $productFactory - * @param StockResolverInterface $stockResolver - * @param StockStateProviderInterface $stockStateProvider */ public function __construct( StockConfigurationInterface $stockConfiguration, StockRegistryProviderInterface $stockRegistryProvider, StockItemRepositoryInterface $stockItemRepository, StockItemCriteriaInterfaceFactory $criteriaFactory, - ProductFactory $productFactory, - StockResolverInterface $stockResolver, - StockStateProviderInterface $stockStateProvider + ProductFactory $productFactory ) { $this->stockConfiguration = $stockConfiguration; $this->stockRegistryProvider = $stockRegistryProvider; $this->stockItemRepository = $stockItemRepository; $this->criteriaFactory = $criteriaFactory; $this->productFactory = $productFactory; - $this->stockResolver = $stockResolver; - $this->stockStateProvider = $stockStateProvider; } /** - * @inheritdoc + * @param int $scopeId + * @return \Magento\CatalogInventory\Api\Data\StockInterface */ - public function getStock($stockId = null) + public function getStock($scopeId = null) { - return $this->stockRegistryProvider->getStock($stockId); + //if (!$scopeId) { + $scopeId = $this->stockConfiguration->getDefaultScopeId(); + //} + return $this->stockRegistryProvider->getStock($scopeId); } /** @@ -99,12 +85,10 @@ class StockRegistry implements StockRegistryInterface */ public function getStockItem($productId, $scopeId = null) { - if (!$scopeId) { - $scopeId = $this->stockConfiguration->getDefaultScopeId(); - } - $stockId = $this->stockResolver->getStockId($productId, $scopeId); - - return $this->stockRegistryProvider->getStockItem($productId, $stockId); + //if (!$scopeId) { + $scopeId = $this->stockConfiguration->getDefaultScopeId(); + //} + return $this->stockRegistryProvider->getStockItem($productId, $scopeId); } /** @@ -115,12 +99,11 @@ class StockRegistry implements StockRegistryInterface */ public function getStockItemBySku($productSku, $scopeId = null) { - if (!$scopeId) { - $scopeId = $this->stockConfiguration->getDefaultScopeId(); - } + //if (!$scopeId) { + $scopeId = $this->stockConfiguration->getDefaultScopeId(); + //} $productId = $this->resolveProductId($productSku); - $stockId = $this->stockResolver->getStockId($productId, $scopeId); - return $this->stockRegistryProvider->getStockItem($productId, $stockId); + return $this->stockRegistryProvider->getStockItem($productId, $scopeId); } /** @@ -130,11 +113,10 @@ class StockRegistry implements StockRegistryInterface */ public function getStockStatus($productId, $scopeId = null) { - if (!$scopeId) { - $scopeId = $this->stockConfiguration->getDefaultScopeId(); - } - $stockId = $this->stockResolver->getStockId($productId, $scopeId); - return $this->stockRegistryProvider->getStockStatus($productId, $stockId); + //if (!$scopeId) { + $scopeId = $this->stockConfiguration->getDefaultScopeId(); + //} + return $this->stockRegistryProvider->getStockStatus($productId, $scopeId); } /** @@ -145,12 +127,11 @@ class StockRegistry implements StockRegistryInterface */ public function getStockStatusBySku($productSku, $scopeId = null) { - if (!$scopeId) { - $scopeId = $this->stockConfiguration->getDefaultScopeId(); - } + //if (!$scopeId) { + $scopeId = $this->stockConfiguration->getDefaultScopeId(); + //} $productId = $this->resolveProductId($productSku); - $stockId = $this->stockResolver->getStockId($productId, $scopeId); - return $this->getStockStatus($productId, $stockId); + return $this->getStockStatus($productId, $scopeId); } /** @@ -161,11 +142,10 @@ class StockRegistry implements StockRegistryInterface */ public function getProductStockStatus($productId, $scopeId = null) { - if (!$scopeId) { - $scopeId = $this->stockConfiguration->getDefaultScopeId(); - } - $stockId = $this->stockResolver->getStockId($productId, $scopeId); - $stockStatus = $this->getStockStatus($productId, $stockId); + //if (!$scopeId) { + $scopeId = $this->stockConfiguration->getDefaultScopeId(); + //} + $stockStatus = $this->getStockStatus($productId, $scopeId); return $stockStatus->getStockStatus(); } @@ -177,12 +157,11 @@ class StockRegistry implements StockRegistryInterface */ public function getProductStockStatusBySku($productSku, $scopeId = null) { - if (!$scopeId) { - $scopeId = $this->stockConfiguration->getDefaultScopeId(); - } + //if (!$scopeId) { + $scopeId = $this->stockConfiguration->getDefaultScopeId(); + //} $productId = $this->resolveProductId($productSku); - $stockId = $this->stockResolver->getStockId($productId, $scopeId); - return $this->getProductStockStatus($productId, $stockId); + return $this->getProductStockStatus($productId, $scopeId); } /** diff --git a/app/code/Magento/CatalogInventory/Model/StockRegistryProvider.php b/app/code/Magento/CatalogInventory/Model/StockRegistryProvider.php index 0e103e2cddd14ff07bccc59a2239ca5d40a1a787..e8f7ae5cc723fb8219aaf9990c1d23017cb35b4e 100644 --- a/app/code/Magento/CatalogInventory/Model/StockRegistryProvider.php +++ b/app/code/Magento/CatalogInventory/Model/StockRegistryProvider.php @@ -15,13 +15,11 @@ use Magento\CatalogInventory\Api\Data\StockStatusInterfaceFactory; use Magento\CatalogInventory\Api\StockCriteriaInterfaceFactory; use Magento\CatalogInventory\Api\StockItemCriteriaInterfaceFactory; use Magento\CatalogInventory\Api\StockStatusCriteriaInterfaceFactory; -use Magento\CatalogInventory\Api\StockConfigurationInterface; use Magento\Store\Model\StoreManagerInterface; /** * Class StockRegistryProvider * @SuppressWarnings(PHPMD.CouplingBetweenObjects) - * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ class StockRegistryProvider implements StockRegistryProviderInterface { @@ -70,11 +68,6 @@ class StockRegistryProvider implements StockRegistryProviderInterface */ protected $stockStatusCriteriaFactory; - /** - * @var StockConfigurationInterface - */ - protected $stockConfiguration; - /** * @var array */ @@ -100,7 +93,6 @@ class StockRegistryProvider implements StockRegistryProviderInterface * @param StockCriteriaInterfaceFactory $stockCriteriaFactory * @param StockItemCriteriaInterfaceFactory $stockItemCriteriaFactory * @param StockStatusCriteriaInterfaceFactory $stockStatusCriteriaFactory - * @param StockConfigurationInterface $stockConfiguration */ public function __construct( StockRepositoryInterface $stockRepository, @@ -111,8 +103,7 @@ class StockRegistryProvider implements StockRegistryProviderInterface StockStatusInterfaceFactory $stockStatusFactory, StockCriteriaInterfaceFactory $stockCriteriaFactory, StockItemCriteriaInterfaceFactory $stockItemCriteriaFactory, - StockStatusCriteriaInterfaceFactory $stockStatusCriteriaFactory, - StockConfigurationInterface $stockConfiguration + StockStatusCriteriaInterfaceFactory $stockStatusCriteriaFactory ) { $this->stockRepository = $stockRepository; $this->stockFactory = $stockFactory; @@ -120,49 +111,43 @@ class StockRegistryProvider implements StockRegistryProviderInterface $this->stockItemFactory = $stockItemFactory; $this->stockStatusRepository = $stockStatusRepository; $this->stockStatusFactory = $stockStatusFactory; + $this->stockCriteriaFactory = $stockCriteriaFactory; $this->stockItemCriteriaFactory = $stockItemCriteriaFactory; $this->stockStatusCriteriaFactory = $stockStatusCriteriaFactory; - $this->stockConfiguration = $stockConfiguration; } /** - * @inheritdoc + * @param int|null $scopeId + * @return \Magento\CatalogInventory\Api\Data\StockInterface */ - public function getStock($stockId) + public function getStock($scopeId) { - if (!isset($this->stocks[$stockId])) { - if ($stockId !== null) { - $stock = $this->stockRepository->get($stockId); - } else { - /** @var \Magento\CatalogInventory\Api\StockCriteriaInterface $criteria */ - $criteria = $this->stockCriteriaFactory->create(); - $criteria->setScopeFilter($this->stockConfiguration->getDefaultScopeId()); - $collection = $this->stockRepository->getList($criteria); - $stock = current($collection->getItems()); - } + if (!isset($this->stocks[$scopeId])) { + $criteria = $this->stockCriteriaFactory->create(); + $criteria->setScopeFilter($scopeId); + $collection = $this->stockRepository->getList($criteria); + $stock = current($collection->getItems()); if ($stock && $stock->getStockId()) { - $this->stocks[$stockId] = $stock; + $this->stocks[$scopeId] = $stock; } else { return $this->stockFactory->create(); } } - return $this->stocks[$stockId]; + return $this->stocks[$scopeId]; } /** * @param int $productId - * @param int $stockId + * @param int $scopeId * @return \Magento\CatalogInventory\Api\Data\StockItemInterface */ - public function getStockItem($productId, $stockId) + public function getStockItem($productId, $scopeId) { - $key = $stockId . '/' . $productId; + $key = $scopeId . '/' . $productId; if (!isset($this->stockItems[$key])) { - /** @var \Magento\CatalogInventory\Api\StockItemCriteriaInterface $criteria */ $criteria = $this->stockItemCriteriaFactory->create(); $criteria->setProductsFilter($productId); - $criteria->setStockFilter($this->getStock($stockId)); $collection = $this->stockItemRepository->getList($criteria); $stockItem = current($collection->getItems()); if ($stockItem && $stockItem->getItemId()) { @@ -176,17 +161,16 @@ class StockRegistryProvider implements StockRegistryProviderInterface /** * @param int $productId - * @param int $stockId + * @param int $scopeId * @return \Magento\CatalogInventory\Api\Data\StockStatusInterface */ - public function getStockStatus($productId, $stockId) + public function getStockStatus($productId, $scopeId) { - $key = $stockId . '/' . $productId; + $key = $scopeId . '/' . $productId; if (!isset($this->stockStatuses[$key])) { - /** @var \Magento\CatalogInventory\Api\stockStatusCriteriaInterface $criteria */ $criteria = $this->stockStatusCriteriaFactory->create(); $criteria->setProductsFilter($productId); - $criteria->addFilter('stock', 'stock_id', $stockId); + $criteria->setScopeFilter($scopeId); $collection = $this->stockStatusRepository->getList($criteria); $stockStatus = current($collection->getItems()); if ($stockStatus && $stockStatus->getProductId()) { diff --git a/app/code/Magento/CatalogInventory/Model/StockResolver.php b/app/code/Magento/CatalogInventory/Model/StockResolver.php deleted file mode 100644 index 8e7c096d37047e7ae2c4cc40da87b6cbcb3f2c16..0000000000000000000000000000000000000000 --- a/app/code/Magento/CatalogInventory/Model/StockResolver.php +++ /dev/null @@ -1,25 +0,0 @@ -<?php -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\CatalogInventory\Model; - -use Magento\CatalogInventory\Model\Spi\StockResolverInterface; - -/** - * Class StockResolver - */ -class StockResolver implements StockResolverInterface -{ - const DEFAULT_STOCK_ID = 1; - - /** - * @inheritdoc - */ - public function getStockId($productId, $websiteId) - { - $stockId = self::DEFAULT_STOCK_ID; - return $stockId; - } -} diff --git a/app/code/Magento/CatalogInventory/Model/StockState.php b/app/code/Magento/CatalogInventory/Model/StockState.php index e64906691ad79ca2e8c65ddfe7738711b628101a..c3d0dc9aef0fd317d0d69e8b1b06b01b5af4f7e7 100644 --- a/app/code/Magento/CatalogInventory/Model/StockState.php +++ b/app/code/Magento/CatalogInventory/Model/StockState.php @@ -9,7 +9,6 @@ use Magento\CatalogInventory\Api\StockConfigurationInterface; use Magento\CatalogInventory\Api\StockStateInterface; use Magento\CatalogInventory\Model\Spi\StockRegistryProviderInterface; use Magento\CatalogInventory\Model\Spi\StockStateProviderInterface; -use Magento\CatalogInventory\Model\Spi\StockResolverInterface; /** * Interface StockState @@ -31,27 +30,19 @@ class StockState implements StockStateInterface */ protected $stockConfiguration; - /** - * @var StockResolverInterface - */ - protected $stockResolver; - /** * @param StockStateProviderInterface $stockStateProvider * @param StockRegistryProviderInterface $stockRegistryProvider * @param StockConfigurationInterface $stockConfiguration - * @param StockResolverInterface $stockResolver */ public function __construct( StockStateProviderInterface $stockStateProvider, StockRegistryProviderInterface $stockRegistryProvider, - StockConfigurationInterface $stockConfiguration, - StockResolverInterface $stockResolver + StockConfigurationInterface $stockConfiguration ) { $this->stockStateProvider = $stockStateProvider; $this->stockRegistryProvider = $stockRegistryProvider; $this->stockConfiguration = $stockConfiguration; - $this->stockResolver = $stockResolver; } /** @@ -64,8 +55,7 @@ class StockState implements StockStateInterface if ($scopeId === null) { $scopeId = $this->stockConfiguration->getDefaultScopeId(); } - $stockId = $this->stockResolver->getStockId($productId, $scopeId); - $stockItem = $this->stockRegistryProvider->getStockItem($productId, $stockId); + $stockItem = $this->stockRegistryProvider->getStockItem($productId, $scopeId); return $this->stockStateProvider->verifyStock($stockItem); } @@ -79,8 +69,7 @@ class StockState implements StockStateInterface if ($scopeId === null) { $scopeId = $this->stockConfiguration->getDefaultScopeId(); } - $stockId = $this->stockResolver->getStockId($productId, $scopeId); - $stockItem = $this->stockRegistryProvider->getStockItem($productId, $stockId); + $stockItem = $this->stockRegistryProvider->getStockItem($productId, $scopeId); return $this->stockStateProvider->verifyNotification($stockItem); } @@ -98,8 +87,7 @@ class StockState implements StockStateInterface if ($scopeId === null) { $scopeId = $this->stockConfiguration->getDefaultScopeId(); } - $stockId = $this->stockResolver->getStockId($productId, $scopeId); - $stockItem = $this->stockRegistryProvider->getStockItem($productId, $stockId); + $stockItem = $this->stockRegistryProvider->getStockItem($productId, $scopeId); return $this->stockStateProvider->checkQty($stockItem, $qty); } @@ -117,8 +105,7 @@ class StockState implements StockStateInterface if ($scopeId === null) { $scopeId = $this->stockConfiguration->getDefaultScopeId(); } - $stockId = $this->stockResolver->getStockId($productId, $scopeId); - $stockItem = $this->stockRegistryProvider->getStockItem($productId, $stockId); + $stockItem = $this->stockRegistryProvider->getStockItem($productId, $scopeId); return $this->stockStateProvider->suggestQty($stockItem, $qty); } @@ -134,8 +121,7 @@ class StockState implements StockStateInterface if ($scopeId === null) { $scopeId = $this->stockConfiguration->getDefaultScopeId(); } - $stockId = $this->stockResolver->getStockId($productId, $scopeId); - $stockItem = $this->stockRegistryProvider->getStockItem($productId, $stockId); + $stockItem = $this->stockRegistryProvider->getStockItem($productId, $scopeId); return $this->stockStateProvider->getStockQty($stockItem); } @@ -150,8 +136,7 @@ class StockState implements StockStateInterface if ($websiteId === null) { $websiteId = $this->stockConfiguration->getDefaultScopeId(); } - $stockId = $this->stockResolver->getStockId($productId, $websiteId); - $stockItem = $this->stockRegistryProvider->getStockItem($productId, $stockId); + $stockItem = $this->stockRegistryProvider->getStockItem($productId, $websiteId); return $this->stockStateProvider->checkQtyIncrements($stockItem, $qty); } @@ -168,8 +153,7 @@ class StockState implements StockStateInterface if ($scopeId === null) { $scopeId = $this->stockConfiguration->getDefaultScopeId(); } - $stockId = $this->stockResolver->getStockId($productId, $scopeId); - $stockItem = $this->stockRegistryProvider->getStockItem($productId, $stockId); + $stockItem = $this->stockRegistryProvider->getStockItem($productId, $scopeId); return $this->stockStateProvider->checkQuoteItemQty($stockItem, $itemQty, $qtyToCheck, $origQty); } } diff --git a/app/code/Magento/CatalogInventory/Observer/AddInventoryDataObserver.php b/app/code/Magento/CatalogInventory/Observer/AddInventoryDataObserver.php index 402807a624217f3989c2adc6f6371c1f3b05cb68..2e9ce4a393fab4de8e9ce06f8cc163aea9a10658 100644 --- a/app/code/Magento/CatalogInventory/Observer/AddInventoryDataObserver.php +++ b/app/code/Magento/CatalogInventory/Observer/AddInventoryDataObserver.php @@ -34,10 +34,7 @@ class AddInventoryDataObserver implements ObserverInterface { $product = $observer->getEvent()->getProduct(); if ($product instanceof \Magento\Catalog\Model\Product) { - $this->stockHelper->assignStatusToProduct( - $product, - $product->getStockStatus() - ); + $this->stockHelper->assignStatusToProduct($product); } } } diff --git a/app/code/Magento/CatalogInventory/Observer/SaveInventoryDataObserver.php b/app/code/Magento/CatalogInventory/Observer/SaveInventoryDataObserver.php index 84c6e31dbac4557fef31dbdd13fa57bb8ee1ef4b..08bf961fb7278d5dc624a637512bd6c3e4fc5a6e 100644 --- a/app/code/Magento/CatalogInventory/Observer/SaveInventoryDataObserver.php +++ b/app/code/Magento/CatalogInventory/Observer/SaveInventoryDataObserver.php @@ -11,7 +11,6 @@ use Magento\CatalogInventory\Api\StockConfigurationInterface; use Magento\CatalogInventory\Api\StockIndexInterface; use Magento\CatalogInventory\Api\StockItemRepositoryInterface; use Magento\CatalogInventory\Api\StockRegistryInterface; -use Magento\CatalogInventory\Model\Spi\StockResolverInterface; use Magento\Framework\Event\Observer as EventObserver; class SaveInventoryDataObserver implements ObserverInterface @@ -36,11 +35,6 @@ class SaveInventoryDataObserver implements ObserverInterface */ protected $stockItemRepository; - /** - * @var StockResolverInterface - */ - protected $stockResolver; - /** * @var array */ @@ -80,20 +74,17 @@ class SaveInventoryDataObserver implements ObserverInterface * @param StockConfigurationInterface $stockConfiguration * @param StockRegistryInterface $stockRegistry * @param StockItemRepositoryInterface $stockItemRepository - * @param StockResolverInterface $stockResolver */ public function __construct( StockIndexInterface $stockIndex, StockConfigurationInterface $stockConfiguration, StockRegistryInterface $stockRegistry, - StockItemRepositoryInterface $stockItemRepository, - StockResolverInterface $stockResolver + StockItemRepositoryInterface $stockItemRepository ) { $this->stockIndex = $stockIndex; $this->stockConfiguration = $stockConfiguration; $this->stockRegistry = $stockRegistry; $this->stockItemRepository = $stockItemRepository; - $this->stockResolver = $stockResolver; } /** @@ -134,8 +125,7 @@ class SaveInventoryDataObserver implements ObserverInterface if (!isset($stockItemData['website_id'])) { $stockItemData['website_id'] = $this->stockConfiguration->getDefaultScopeId(); } - $stockItemData['stock_id'] = $this->stockResolver - ->getStockId($stockItemData['product_id'], $stockItemData['website_id']); + $stockItemData['stock_id'] = $this->stockRegistry->getStock($stockItemData['website_id'])->getStockId(); foreach ($this->paramListToCheck as $dataKey => $configPath) { if (null !== $product->getData($configPath['item']) && null === $product->getData($configPath['config'])) { diff --git a/app/code/Magento/CatalogInventory/Test/Unit/Api/StockRegistryTest.php b/app/code/Magento/CatalogInventory/Test/Unit/Api/StockRegistryTest.php index 435defef554e54a259e707d770b9cc894ccba025..02c631727a4b564dfebad116b996c0a078420c39 100644 --- a/app/code/Magento/CatalogInventory/Test/Unit/Api/StockRegistryTest.php +++ b/app/code/Magento/CatalogInventory/Test/Unit/Api/StockRegistryTest.php @@ -58,7 +58,6 @@ class StockRegistryTest extends \PHPUnit_Framework_TestCase protected $product; protected $productId = 111; - protected $stockId = 112; protected $productSku = 'simple'; protected $websiteId = 111; @@ -136,7 +135,7 @@ class StockRegistryTest extends \PHPUnit_Framework_TestCase public function testGetStock() { - $this->assertEquals($this->stock, $this->stockRegistry->getStock($this->stockId)); + $this->assertEquals($this->stock, $this->stockRegistry->getStock($this->websiteId)); } public function testGetStockItem() diff --git a/app/code/Magento/CatalogInventory/Test/Unit/Helper/StockTest.php b/app/code/Magento/CatalogInventory/Test/Unit/Helper/StockTest.php index 65173103377f4266eb5ce169d52b35863b74cfcd..cb4209de616e798498590461c9db2e3e1891657d 100644 --- a/app/code/Magento/CatalogInventory/Test/Unit/Helper/StockTest.php +++ b/app/code/Magento/CatalogInventory/Test/Unit/Helper/StockTest.php @@ -37,11 +37,6 @@ class StockTest extends \PHPUnit_Framework_TestCase */ protected $statusFactoryMock; - /** - * @var \Magento\CatalogInventory\Model\Spi\StockResolverInterface|\PHPUnit_Framework_MockObject_MockObject - */ - protected $stockResolverMock; - protected function setUp() { $this->stockRegistryProviderMock = $this->getMockBuilder( @@ -60,26 +55,18 @@ class StockTest extends \PHPUnit_Framework_TestCase ->disableOriginalConstructor() ->setMethods(['create']) ->getMock(); - $this->stockResolverMock = - $this->getMockBuilder('Magento\CatalogInventory\Model\Spi\StockResolverInterface') - ->disableOriginalConstructor() - ->setMethods(['getStockId']) - ->getMock(); $this->stock = new Stock( $this->storeManagerMock, $this->scopeConfigMock, $this->statusFactoryMock, - $this->stockRegistryProviderMock, - $this->stockResolverMock + $this->stockRegistryProviderMock ); } public function testAssignStatusToProduct() { - $websiteId = 0; - $productId = 2; - $stockId = 3; - $status = 1; + $websiteId = 1; + $status = 'test'; $stockStatusMock = $this->getMockBuilder('Magento\CatalogInventory\Api\Data\StockStatusInterface') ->disableOriginalConstructor() @@ -106,23 +93,15 @@ class StockTest extends \PHPUnit_Framework_TestCase $productMock->expects($this->once()) ->method('setIsSalable') ->with($status); - $productMock->expects($this->once()) - ->method('getId') - ->willReturn($productId); - $this->stockResolverMock->expects($this->once()) - ->method('getStockId') - ->with($productId, $websiteId) - ->willReturn($stockId); $this->assertNull($this->stock->assignStatusToProduct($productMock)); } public function testAddStockStatusToProducts() { $storeId = 1; - $websiteId = 0; $productId = 2; - $stockId = 3; - $status = 1; + $status = 'test'; + $productMock = $this->getMockBuilder('Magento\Catalog\Model\Product') ->disableOriginalConstructor() ->setMethods(['setIsSalable', 'getId']) @@ -158,21 +137,14 @@ class StockTest extends \PHPUnit_Framework_TestCase $storeMock = $this->getMockBuilder('Magento\Store\Model\Store') ->disableOriginalConstructor() ->getMock(); - $storeMock->expects($this->once()) - ->method('getWebsiteId') - ->willReturn($websiteId); $this->storeManagerMock->expects($this->once()) ->method('getStore') - ->with($storeId) ->willReturn($storeMock); $this->stockRegistryProviderMock->expects($this->once()) ->method('getStockStatus') ->withAnyParameters() ->willReturn($stockStatusMock); - $this->stockResolverMock->expects($this->once()) - ->method('getStockId') - ->with($productId, $websiteId) - ->willReturn($stockId); + $this->assertNull($this->stock->addStockStatusToProducts($productCollectionMock)); } diff --git a/app/code/Magento/CatalogInventory/Test/Unit/Model/Spi/StockRegistryProviderTest.php b/app/code/Magento/CatalogInventory/Test/Unit/Model/Spi/StockRegistryProviderTest.php index 5cf08ca76f3a35e8ad7a91ddae0eba033997a957..8328208440b80f2200511934d54fcb1886409035 100644 --- a/app/code/Magento/CatalogInventory/Test/Unit/Model/Spi/StockRegistryProviderTest.php +++ b/app/code/Magento/CatalogInventory/Test/Unit/Model/Spi/StockRegistryProviderTest.php @@ -9,20 +9,45 @@ use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHe /** * Class StockRegistryProviderTest + * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + * @SuppressWarnings(PHPMD.TooManyFields) */ class StockRegistryProviderTest extends \PHPUnit_Framework_TestCase { + /** @var ObjectManagerHelper */ + protected $objectManagerHelper; + /** * @var \Magento\CatalogInventory\Model\Spi\StockRegistryProviderInterface|\PHPUnit_Framework_MockObject_MockObject */ protected $stockRegistryProvider; + /** + * @var \Magento\CatalogInventory\Api\Data\StockInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $stock; + + /** + * @var \Magento\CatalogInventory\Api\Data\StockItemInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $stockItem; + /** * @var \Magento\CatalogInventory\Api\Data\StockStatusInterface|\PHPUnit_Framework_MockObject_MockObject */ protected $stockStatus; + /** + * @var \Magento\CatalogInventory\Api\Data\StockStatusInterfaceFactory|\PHPUnit_Framework_MockObject_MockObject + */ + protected $stockStatusFactory; + + /** + * @var \Magento\CatalogInventory\Api\Data\StockItemInterfaceFactory|\PHPUnit_Framework_MockObject_MockObject + */ + protected $stockItemFactory; + /** * @var \Magento\CatalogInventory\Api\Data\StockInterfaceFactory|\PHPUnit_Framework_MockObject_MockObject */ @@ -58,6 +83,11 @@ class StockRegistryProviderTest extends \PHPUnit_Framework_TestCase */ protected $stockStatusCriteriaFactory; + /** + * @var \Magento\CatalogInventory\Api\StockCriteriaInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $stockCriteria; + /** * @var \Magento\CatalogInventory\Api\StockItemCriteriaInterface|\PHPUnit_Framework_MockObject_MockObject */ @@ -68,88 +98,132 @@ class StockRegistryProviderTest extends \PHPUnit_Framework_TestCase */ protected $stockStatusCriteria; - /** - * @var \Magento\CatalogInventory\Api\StockConfigurationInterface|\PHPUnit_Framework_MockObject_MockObject - */ - protected $stockConfiguration; + protected $productId = 111; + protected $productSku = 'simple'; + protected $scopeId = 111; /** - * @var array + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ - protected $productData = [ - 'stock_id' => 111, - 'product_id' => 112, - 'product_sku' => 'simple', - 'scope_id' => 113 - ]; - protected function setUp() { - $objectManagerHelper = new ObjectManagerHelper($this); + $this->objectManagerHelper = new ObjectManagerHelper($this); - $this->stockFactory = $this->getMockBuilder('\Magento\CatalogInventory\Api\Data\StockInterfaceFactory') - ->disableOriginalConstructor() - ->setMethods(['create']) - ->getMock(); - $stockItemFactory = $this->getMockBuilder('\Magento\CatalogInventory\Api\Data\StockItemInterfaceFactory') - ->disableOriginalConstructor() - ->setMethods(['create']) - ->getMock(); - $stockStatusFactory = $this->getMockBuilder( - '\Magento\CatalogInventory\Api\Data\StockStatusInterfaceFactory' - ) - ->disableOriginalConstructor() - ->setMethods(['create']) - ->getMock(); - $stockStatusFactory->expects($this->any())->method('create')->willReturn($this->stockStatus); - $this->stockCriteriaFactory = $this->getMockBuilder( - 'Magento\CatalogInventory\Api\StockCriteriaInterfaceFactory' - ) - ->disableOriginalConstructor() - ->setMethods(['create']) - ->getMock(); - $this->stockItemCriteriaFactory = $this->getMockBuilder( - 'Magento\CatalogInventory\Api\StockItemCriteriaInterfaceFactory' - ) - ->disableOriginalConstructor() - ->setMethods(['create']) - ->getMock(); - $this->stockStatusCriteriaFactory = $this->getMockBuilder( - 'Magento\CatalogInventory\Api\StockStatusCriteriaInterfaceFactory' - ) - ->disableOriginalConstructor() - ->setMethods(['create']) - ->getMock(); + $this->stock = $this->getMockForAbstractClass( + 'Magento\CatalogInventory\Api\Data\StockInterface', + ['__wakeup', 'getStockId'], + '', + false + ); + $this->stockItem = $this->getMockForAbstractClass( + 'Magento\CatalogInventory\Api\Data\StockItemInterface', + ['__wakeup', 'getItemId'], + '', + false + ); + $this->stockStatus = $this->getMockForAbstractClass( + 'Magento\CatalogInventory\Api\Data\StockStatusInterface', + ['__wakeup', 'getProductId'], + '', + false + ); + + $this->stockFactory = $this->getMock( + '\Magento\CatalogInventory\Api\Data\StockInterfaceFactory', + ['create'], + [], + '', + false + ); + $this->stockFactory->expects($this->any())->method('create')->willReturn($this->stock); + + $this->stockItemFactory = $this->getMock( + '\Magento\CatalogInventory\Api\Data\StockItemInterfaceFactory', + ['create'], + [], + '', + false + ); + $this->stockItemFactory->expects($this->any())->method('create')->willReturn($this->stockItem); + + $this->stockStatusFactory = $this->getMock( + '\Magento\CatalogInventory\Api\Data\StockStatusInterfaceFactory', + ['create'], + [], + '', + false + ); + $this->stockStatusFactory->expects($this->any())->method('create')->willReturn($this->stockStatus); $this->stockRepository = $this->getMockBuilder('\Magento\CatalogInventory\Api\StockRepositoryInterface') ->disableOriginalConstructor() ->getMock(); + $this->stockItemRepository = $this->getMockBuilder('\Magento\CatalogInventory\Api\StockItemRepositoryInterface') ->disableOriginalConstructor() ->getMock(); + $this->stockStatusRepository = $this->getMockBuilder( '\Magento\CatalogInventory\Api\StockStatusRepositoryInterface' ) ->disableOriginalConstructor() ->getMock(); - $this->stockConfiguration = $this->getMockBuilder('Magento\CatalogInventory\Api\StockConfigurationInterface') - ->disableOriginalConstructor() - ->setMethods(['getDefaultScopeId']) - ->getMockForAbstractClass(); - $this->stockRegistryProvider = $objectManagerHelper->getObject( + $this->stockCriteriaFactory = $this->getMock( + 'Magento\CatalogInventory\Api\StockCriteriaInterfaceFactory', + ['create'], + [], + '', + false + ); + $this->stockCriteria = $this->getMockForAbstractClass( + 'Magento\CatalogInventory\Api\StockCriteriaInterface', + ['setScopeFilter'], + '', + false + ); + + $this->stockItemCriteriaFactory = $this->getMock( + 'Magento\CatalogInventory\Api\StockItemCriteriaInterfaceFactory', + ['create'], + [], + '', + false + ); + $this->stockItemCriteria = $this->getMockForAbstractClass( + 'Magento\CatalogInventory\Api\StockItemCriteriaInterface', + ['setProductsFilter', 'setScopeFilter'], + '', + false + ); + + $this->stockStatusCriteriaFactory = $this->getMock( + 'Magento\CatalogInventory\Api\StockStatusCriteriaInterfaceFactory', + ['create'], + [], + '', + false + ); + $this->stockStatusCriteria = $this->getMockForAbstractClass( + 'Magento\CatalogInventory\Api\StockStatusCriteriaInterface', + ['setProductsFilter', 'setScopeFilter'], + '', + false + ); + + $this->stockRegistryProvider = $this->objectManagerHelper->getObject( '\Magento\CatalogInventory\Model\StockRegistryProvider', [ 'stockRepository' => $this->stockRepository, 'stockFactory' => $this->stockFactory, 'stockItemRepository' => $this->stockItemRepository, - 'stockItemFactory' => $stockItemFactory, + 'stockItemFactory' => $this->stockItemFactory, 'stockStatusRepository' => $this->stockStatusRepository, - 'stockStatusFactory' => $stockStatusFactory, + 'stockStatusFactory' => $this->stockStatusFactory, + 'stockCriteriaFactory' => $this->stockCriteriaFactory, 'stockItemCriteriaFactory' => $this->stockItemCriteriaFactory, - 'stockStatusCriteriaFactory' => $this->stockStatusCriteriaFactory, - 'stockConfiguration' => $this->stockConfiguration + 'stockStatusCriteriaFactory' => $this->stockStatusCriteriaFactory ] ); } @@ -159,114 +233,63 @@ class StockRegistryProviderTest extends \PHPUnit_Framework_TestCase $this->stockRegistryProvider = null; } - public function testGetStockWithStock() + public function testGetStock() { - $stock = $this->getMockBuilder('Magento\CatalogInventory\Api\Data\StockInterface') - ->disableOriginalConstructor() - ->setMethods(['getStockId']) - ->getMockForAbstractClass(); - $this->stockFactory->expects($this->any())->method('create')->willReturn($stock); - $stock->expects($this->once())->method('getStockId')->willReturn($this->productData['stock_id']); - $this->stockRepository->expects($this->once())->method('get')->willReturn($stock); - $this->assertEquals($stock, $this->stockRegistryProvider->getStock($this->productData['stock_id'])); - } - - public function testGetStockWithoutStock() - { - $this->stockConfiguration->expects($this->once())->method('getDefaultScopeId') - ->willReturn($this->productData['scope_id']); - $stock = $this->getMockBuilder('Magento\CatalogInventory\Api\Data\StockInterface') - ->disableOriginalConstructor() - ->setMethods(['getStockId']) - ->getMockForAbstractClass(); - $stock->expects($this->once())->method('getStockId')->willReturn($this->productData['stock_id']); - $stockCollection = $this->getMockBuilder('Magento\CatalogInventory\Api\Data\StockCollectionInterface') - ->disableOriginalConstructor() - ->setMethods(['getItems']) - ->getMockForAbstractClass(); - $stockCriteria = $this->getMockBuilder('\Magento\CatalogInventory\Api\StockCriteriaInterface') - ->disableOriginalConstructor() - ->setMethods(['getItems']) - ->getMockForAbstractClass(); - $stockCriteria->expects($this->once())->method('setScopeFilter')->with($this->productData['scope_id']) - ->willReturnSelf(); - $this->stockCriteriaFactory->expects($this->once())->method('create')->willReturn($stockCriteria); - $this->stockRepository->expects($this->once())->method('getList') - ->with($stockCriteria)->willReturn($stockCollection); - $stockCollection->expects($this->once())->method('getItems')->willReturn([$stock]); - $this->assertEquals($stock, $this->stockRegistryProvider->getStock(null)); + $this->stockCriteriaFactory->expects($this->once())->method('create')->willReturn($this->stockCriteria); + $this->stockCriteria->expects($this->once())->method('setScopeFilter')->willReturn(null); + $stockCollection = $this->getMock( + '\Magento\CatalogInventory\Model\ResourceModel\Stock\Collection', + ['getFirstItem', '__wakeup', 'getItems'], + [], + '', + false + ); + $stockCollection->expects($this->once())->method('getItems')->willReturn([$this->stock]); + $this->stockRepository->expects($this->once())->method('getList')->willReturn($stockCollection); + $this->stock->expects($this->once())->method('getStockId')->willReturn(true); + $this->assertEquals($this->stock, $this->stockRegistryProvider->getStock($this->scopeId)); } public function testGetStockItem() { - $stock = $this->getMockBuilder('Magento\CatalogInventory\Api\Data\StockInterface') - ->disableOriginalConstructor() - ->setMethods(['getStockId']) - ->getMockForAbstractClass(); - $this->stockRepository->expects($this->once())->method('get')->willReturn($stock); - $stockItemCriteria = $this->getMockBuilder('Magento\CatalogInventory\Api\StockItemCriteriaInterface') - ->disableOriginalConstructor() - ->setMethods(['setProductsFilter', 'setStockFilter']) - ->getMockForAbstractClass(); - $this->stockItemCriteriaFactory->expects($this->once())->method('create')->willReturn($stockItemCriteria); - $stockItemCriteria->expects($this->once())->method('setProductsFilter')->with($this->productData['product_id']) - ->willReturnSelf(); - $stock->expects($this->once())->method('getStockId')->willReturn($this->productData['stock_id']); - $stockItemCriteria->expects($this->once())->method('setStockFilter')->with($stock) - ->willReturnSelf(); - $stockItemCollection = $this->getMockBuilder( - '\Magento\CatalogInventory\Model\ResourceModel\Stock\Item\Collection' - ) - ->disableOriginalConstructor() - ->setMethods(['getFirstItem', 'getItems']) - ->getMock(); - $stockItem = $this->getMockBuilder('Magento\CatalogInventory\Api\Data\StockItemInterface') - ->disableOriginalConstructor() - ->setMethods(['getItemId']) - ->getMockForAbstractClass(); - $stockItemCollection->expects($this->once())->method('getItems')->willReturn([$stockItem]); + $this->stockItemCriteriaFactory->expects($this->once())->method('create')->willReturn($this->stockItemCriteria); + $this->stockItemCriteria->expects($this->once())->method('setProductsFilter')->willReturn(null); + $stockItemCollection = $this->getMock( + '\Magento\CatalogInventory\Model\ResourceModel\Stock\Item\Collection', + ['getFirstItem', '__wakeup', 'getItems'], + [], + '', + false + ); + $stockItemCollection->expects($this->once())->method('getItems')->willReturn([$this->stockItem]); $this->stockItemRepository->expects($this->once())->method('getList')->willReturn($stockItemCollection); - $stockItem->expects($this->once())->method('getItemId')->willReturn(true); + $this->stockItem->expects($this->once())->method('getItemId')->willReturn(true); $this->assertEquals( - $stockItem, - $this->stockRegistryProvider->getStockItem($this->productData['product_id'], $this->productData['stock_id']) + $this->stockItem, + $this->stockRegistryProvider->getStockItem($this->productId, $this->scopeId) ); } public function testGetStockStatus() { - $stockStatusCriteria = $this->getMockBuilder('Magento\CatalogInventory\Api\StockStatusCriteriaInterface') - ->disableOriginalConstructor() - ->setMethods(['setProductsFilter', 'addFilter']) - ->getMockForAbstractClass(); $this->stockStatusCriteriaFactory->expects($this->once()) ->method('create') - ->willReturn($stockStatusCriteria); - $stockStatusCriteria->expects($this->once())->method('setProductsFilter') - ->with($this->productData['product_id']) - ->willReturnSelf(); - $stockStatusCriteria->expects($this->once())->method('addFilter') - ->with('stock', 'stock_id', $this->productData['stock_id']) - ->willReturnSelf(); - $stockStatusCollection = $this->getMockBuilder( - '\Magento\CatalogInventory\Model\ResourceModel\Stock\Status\Collection' - ) - ->disableOriginalConstructor() - ->setMethods(['getFirstItem', 'getItems']) - ->getMock(); - $stockStatus = $this->getMockBuilder('Magento\CatalogInventory\Api\Data\StockStatusInterface') - ->disableOriginalConstructor() - ->setMethods(['getProductId']) - ->getMockForAbstractClass(); - $stockStatusCollection->expects($this->once())->method('getItems')->willReturn([$stockStatus]); - $stockStatus->expects($this->once())->method('getProductId')->willReturn($this->productData['product_id']); + ->willReturn($this->stockStatusCriteria); + $this->stockStatusCriteria->expects($this->once())->method('setScopeFilter')->willReturn(null); + $this->stockStatusCriteria->expects($this->once())->method('setProductsFilter')->willReturn(null); + $stockStatusCollection = $this->getMock( + '\Magento\CatalogInventory\Model\ResourceModel\Stock\Status\Collection', + ['getFirstItem', '__wakeup', 'getItems'], + [], + '', + false + ); + $stockStatusCollection->expects($this->once())->method('getItems')->willReturn([$this->stockStatus]); $this->stockStatusRepository->expects($this->once())->method('getList')->willReturn($stockStatusCollection); + $this->stockStatus->expects($this->once())->method('getProductId')->willReturn($this->productId); $this->assertEquals( - $stockStatus, - $this->stockRegistryProvider->getStockStatus( - $this->productData['product_id'], - $this->productData['stock_id'] - ) + $this->stockStatus, + $this->stockRegistryProvider->getStockStatus($this->productId, $this->scopeId) ); } } diff --git a/app/code/Magento/CatalogInventory/Test/Unit/Model/Stock/ItemTest.php b/app/code/Magento/CatalogInventory/Test/Unit/Model/Stock/ItemTest.php index a81f930ccb6ce51ef9cab945d67498e7b0e46638..27188a0efd3520d18b7e93d83e0485bdd30f64c4 100644 --- a/app/code/Magento/CatalogInventory/Test/Unit/Model/Stock/ItemTest.php +++ b/app/code/Magento/CatalogInventory/Test/Unit/Model/Stock/ItemTest.php @@ -63,9 +63,9 @@ class ItemTest extends \PHPUnit_Framework_TestCase protected $resource; /** - * @var \Magento\CatalogInventory\Api\StockRegistryInterface|\PHPUnit_Framework_MockObject_MockObject + * @var \Magento\CatalogInventory\Model\ResourceModel\Stock\Item\Collection|\PHPUnit_Framework_MockObject_MockObject */ - protected $stockRegistry; + protected $resourceCollection; /** * @var int @@ -117,8 +117,13 @@ class ItemTest extends \PHPUnit_Framework_TestCase false ); - $this->stockRegistry = $this->getMockBuilder('Magento\CatalogInventory\Api\StockRegistryInterface') - ->getMockForAbstractClass(); + $this->resourceCollection = $this->getMock( + 'Magento\CatalogInventory\Model\ResourceModel\Stock\Item\Collection', + [], + [], + '', + false + ); $this->objectManagerHelper = new ObjectManagerHelper($this); @@ -132,7 +137,7 @@ class ItemTest extends \PHPUnit_Framework_TestCase 'stockConfiguration' => $this->stockConfiguration, 'stockItemRepository' => $this->stockItemRepository, 'resource' => $this->resource, - 'stockRegistry' => $this->stockRegistry + 'stockItemRegistry' => $this->resourceCollection ] ); } @@ -452,14 +457,4 @@ class ItemTest extends \PHPUnit_Framework_TestCase ], ]; } - - public function testGetStockId() - { - $stockId = 1; - $stock = $this->getMockBuilder('Magento\CatalogInventory\Api\Data\StockInterface') - ->getMockForAbstractClass(); - $this->stockRegistry->expects($this->once())->method('getStock')->willReturn($stock); - $stock->expects($this->once())->method('getStockId')->willReturn($stockId); - $this->assertEquals($stockId, $this->item->getStockId()); - } } diff --git a/app/code/Magento/CatalogInventory/Test/Unit/Observer/AddInventoryDataObserverTest.php b/app/code/Magento/CatalogInventory/Test/Unit/Observer/AddInventoryDataObserverTest.php index 9688a418119027ae889d39a296aa861fc2f27d5d..68a73ac1eecaae3c6a075d73697a402b3b9a37c8 100644 --- a/app/code/Magento/CatalogInventory/Test/Unit/Observer/AddInventoryDataObserverTest.php +++ b/app/code/Magento/CatalogInventory/Test/Unit/Observer/AddInventoryDataObserverTest.php @@ -57,24 +57,17 @@ class AddInventoryDataObserverTest extends \PHPUnit_Framework_TestCase public function testAddInventoryData() { - $stockStatus = true; - $product = $this->getMockBuilder('Magento\Catalog\Model\Product') ->disableOriginalConstructor() - ->setMethods(['getStockStatus']) ->getMock(); - $product->expects($this->once()) - ->method('getStockStatus') - ->will($this->returnValue($stockStatus)); - $this->event->expects($this->once()) ->method('getProduct') ->will($this->returnValue($product)); $this->stockHelper->expects($this->once()) ->method('assignStatusToProduct') - ->with($product, $stockStatus) + ->with($product) ->will($this->returnSelf()); $this->observer->execute($this->eventObserver); diff --git a/app/code/Magento/CatalogInventory/Test/Unit/Observer/SaveInventoryDataObserverTest.php b/app/code/Magento/CatalogInventory/Test/Unit/Observer/SaveInventoryDataObserverTest.php index 17ca09b6e24fdf54eb566a71890820076b928ce3..96604e75d92946e9cf614139db7ddda4558cec22 100644 --- a/app/code/Magento/CatalogInventory/Test/Unit/Observer/SaveInventoryDataObserverTest.php +++ b/app/code/Magento/CatalogInventory/Test/Unit/Observer/SaveInventoryDataObserverTest.php @@ -19,26 +19,6 @@ class SaveInventoryDataObserverTest extends \PHPUnit_Framework_TestCase */ protected $stockIndex; - /** - * @var \Magento\CatalogInventory\Api\StockConfigurationInterface|\PHPUnit_Framework_MockObject_MockObject - */ - protected $stockConfiguration; - - /** - * @var \Magento\CatalogInventory\Model\Spi\stockResolverInterface|\PHPUnit_Framework_MockObject_MockObject - */ - protected $stockResolver; - - /** - * @var \Magento\CatalogInventory\Api\StockRegistryInterface|\PHPUnit_Framework_MockObject_MockObject - */ - protected $stockRegistry; - - /** - * @var \Magento\CatalogInventory\Api\StockItemRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject - */ - protected $stockItemRepository; - /** * @var \Magento\Framework\Event|\PHPUnit_Framework_MockObject_MockObject */ @@ -51,30 +31,12 @@ class SaveInventoryDataObserverTest extends \PHPUnit_Framework_TestCase protected function setUp() { - $this->stockIndex = $this->getMockBuilder('Magento\CatalogInventory\Api\StockIndexInterface') - ->disableOriginalConstructor() - ->setMethods(['rebuild']) - ->getMockForAbstractClass(); - - $this->stockConfiguration = $this->getMockBuilder('Magento\CatalogInventory\Api\StockConfigurationInterface') - ->disableOriginalConstructor() - ->setMethods(['getDefaultScopeId']) - ->getMockForAbstractClass(); - - $this->stockResolver = $this->getMockBuilder('Magento\CatalogInventory\Model\Spi\StockResolverInterface') - ->disableOriginalConstructor() - ->setMethods(['getStockId']) - ->getMockForAbstractClass(); - - $this->stockRegistry = $this->getMockBuilder('Magento\CatalogInventory\Api\StockRegistryInterface') - ->disableOriginalConstructor() - ->setMethods(['getStockItem']) - ->getMockForAbstractClass(); - - $this->stockItemRepository = $this->getMockBuilder('Magento\CatalogInventory\Api\StockItemRepositoryInterface') - ->disableOriginalConstructor() - ->setMethods(['save']) - ->getMockForAbstractClass(); + $this->stockIndex = $this->getMockForAbstractClass( + 'Magento\CatalogInventory\Api\StockIndexInterface', + ['rebuild'], + '', + false + ); $this->event = $this->getMockBuilder('Magento\Framework\Event') ->disableOriginalConstructor() @@ -94,15 +56,11 @@ class SaveInventoryDataObserverTest extends \PHPUnit_Framework_TestCase 'Magento\CatalogInventory\Observer\SaveInventoryDataObserver', [ 'stockIndex' => $this->stockIndex, - 'stockConfiguration' => $this->stockConfiguration, - 'stockResolver' => $this->stockResolver, - 'stockRegistry' => $this->stockRegistry, - 'stockItemRepository' => $this->stockItemRepository ] ); } - public function testSaveInventoryDataWithoutStockData() + public function testSaveInventoryData() { $productId = 4; $websiteId = 5; @@ -134,49 +92,4 @@ class SaveInventoryDataObserverTest extends \PHPUnit_Framework_TestCase $this->observer->execute($this->eventObserver); } - - public function testSaveInventoryDataWithStockData() - { - $stockItemData = [ - 'qty' => 4, - 'product_id' => 2, - 'website_id' => 3, - 'stock_id' => 1, - 'qty_correction' => -1 - ]; - - $product = $this->getMock( - 'Magento\Catalog\Model\Product', - ['getStockData', 'getId', 'getData'], - [], - '', - false - ); - $product->expects($this->exactly(2))->method('getStockData')->will($this->returnValue( - ['qty' => $stockItemData['qty']] - )); - $product->expects($this->once())->method('getId')->will($this->returnValue($stockItemData['product_id'])); - $product->expects($this->any())->method('getData')->willReturnMap( - [ - ['stock_data/original_inventory_qty', null, $stockItemData['qty']+1] - ] - ); - $this->stockConfiguration->expects($this->once())->method('getDefaultScopeId') - ->willReturn($stockItemData['website_id']); - $this->stockResolver->expects($this->once())->method('getStockId') - ->with($stockItemData['product_id'], $stockItemData['website_id']) - ->willReturn($stockItemData['stock_id']); - $stockItem = $this->getMockBuilder('\Magento\CatalogInventory\Api\Data\StockItemInterface') - ->disableOriginalConstructor() - ->setMethods(['addData']) - ->getMockForAbstractClass(); - $this->stockRegistry->expects($this->once())->method('getStockItem') - ->with($stockItemData['product_id'], $stockItemData['website_id']) - ->willReturn($stockItem); - $stockItem->expects($this->once())->method('addData')->with($stockItemData)->willReturnSelf(); - $this->stockItemRepository->expects($this->once())->method('save')->with($stockItem); - $this->event->expects($this->once())->method('getProduct')->will($this->returnValue($product)); - - $this->observer->execute($this->eventObserver); - } } diff --git a/app/code/Magento/CatalogInventory/etc/di.xml b/app/code/Magento/CatalogInventory/etc/di.xml index 40f9bf2d1275d44e8822cd021fd9610b00ad71c6..fbce94514ebff09f03060a95ca5bea4a5c698fcf 100644 --- a/app/code/Magento/CatalogInventory/etc/di.xml +++ b/app/code/Magento/CatalogInventory/etc/di.xml @@ -30,8 +30,7 @@ <preference for="Magento\CatalogInventory\Model\Spi\StockRegistryProviderInterface" type="Magento\CatalogInventory\Model\StockRegistryProvider" /> <preference for="Magento\CatalogInventory\Model\Spi\StockStateProviderInterface" type="Magento\CatalogInventory\Model\StockStateProvider" /> - <preference for="Magento\CatalogInventory\Model\Spi\StockResolverInterface" type="Magento\CatalogInventory\Model\StockResolver" /> - + <preference for="Magento\CatalogInventory\Model\ResourceModel\QtyCounterInterface" type="\Magento\CatalogInventory\Model\ResourceModel\Stock" /> <type name="Magento\Catalog\Model\Product\Attribute\Repository"> <plugin name="filterCustomAttribute" type="Magento\CatalogInventory\Model\Plugin\FilterCustomAttribute" /> diff --git a/app/code/Magento/ConfigurableProduct/Test/Unit/Model/ResourceModel/Product/Type/ConfigurableTest.php b/app/code/Magento/ConfigurableProduct/Test/Unit/Model/ResourceModel/Product/Type/ConfigurableTest.php index ca218cf2ea5b20eaef4a636e2506898ccb9931e9..833ca223a7b9b7ebf1ccc0cde42de3b63e5a166a 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Unit/Model/ResourceModel/Product/Type/ConfigurableTest.php +++ b/app/code/Magento/ConfigurableProduct/Test/Unit/Model/ResourceModel/Product/Type/ConfigurableTest.php @@ -30,20 +30,35 @@ class ConfigurableTest extends \PHPUnit_Framework_TestCase */ protected $relation; + /** + * @var \Magento\Framework\Model\Entity\MetadataPool|\PHPUnit_Framework_MockObject_MockObject + */ + protected $metadataPool; + protected function setUp() { $connectionMock = $this->getMockBuilder('\Magento\Framework\DB\Adapter\AdapterInterface')->getMock(); $this->resource = $this->getMock('Magento\Framework\App\ResourceConnection', [], [], '', false); $this->resource->expects($this->any())->method('getConnection')->will($this->returnValue($connectionMock)); + $this->relation = $this->getMock('Magento\Catalog\Model\ResourceModel\Product\Relation', [], [], '', false); + $metadata = $this->getMock('Magento\Framework\Model\Entity\EntityMetadata', [], [], '', false); + + $this->metadataPool = $this->getMock('Magento\Framework\Model\Entity\MetadataPool', [], [], '', false); + $this->metadataPool->expects($this->any()) + ->method('getMetadata') + ->with(\Magento\Catalog\Api\Data\ProductInterface::class) + ->willReturn($metadata); + $this->objectManagerHelper = new ObjectManagerHelper($this); $this->configurable = $this->objectManagerHelper->getObject( 'Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable', [ 'resource' => $this->resource, - 'catalogProductRelation' => $this->relation + 'catalogProductRelation' => $this->relation, + 'metadataPool' => $this->metadataPool ] ); } diff --git a/app/code/Magento/Downloadable/view/adminhtml/web/downloadable-type-handler.js b/app/code/Magento/Downloadable/view/adminhtml/web/downloadable-type-handler.js index 12521c18ca6c17c335f758c82311832dcc6ef2ae..e8e61c26b49cfb7e318d712e65b05f920c0a0f73 100644 --- a/app/code/Magento/Downloadable/view/adminhtml/web/downloadable-type-handler.js +++ b/app/code/Magento/Downloadable/view/adminhtml/web/downloadable-type-handler.js @@ -65,7 +65,10 @@ define([ if (productType.type.current === 'downloadable') { weight.change(false); weight.$weightSwitcher().one('change', function () { - $(document).trigger('setTypeProduct', null); + $(document).trigger( + 'setTypeProduct', + productType.type.init === 'downloadable' ? 'virtual' : productType.type.init + ); }); this.show(); } else { diff --git a/app/code/Magento/Paypal/etc/adminhtml/system.xml b/app/code/Magento/Paypal/etc/adminhtml/system.xml index d716794f5ca8e67649354ac71a070af028661239..545dc858eee17321cf00ff06e79d73277a8c2707 100644 --- a/app/code/Magento/Paypal/etc/adminhtml/system.xml +++ b/app/code/Magento/Paypal/etc/adminhtml/system.xml @@ -51,6 +51,7 @@ <group id="wpp_usuk" sortOrder="40" extends="payment_us/paypal_payment_gateways/paypal_payflowpro_with_express_checkout"> <label>Payments Pro (Includes Express Checkout)</label> <attribute type="activity_path">payment/paypal_payment_pro/active</attribute> + <more_url>https://www.paypal.com/us/webapps/mpp/paypal-payments-pro?partner_id=NB9WWHYEMVUMS</more_url> <group id="paypal_payflow_required" translate="label" showInDefault="1" showInWebsite="1" sortOrder="10"> <field id="enable_paypal_payflow"> <attribute type="shared">0</attribute> diff --git a/app/code/Magento/Ui/view/base/web/js/form/components/button.js b/app/code/Magento/Ui/view/base/web/js/form/components/button.js new file mode 100644 index 0000000000000000000000000000000000000000..b5373ff1648b7f2c3db97e8333551781c09b09e1 --- /dev/null +++ b/app/code/Magento/Ui/view/base/web/js/form/components/button.js @@ -0,0 +1,103 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +define([ + 'uiElement', + 'uiRegistry', + 'uiLayout', + 'mageUtils' +], function (Element, registry, layout, utils) { + 'use strict'; + + return Element.extend({ + defaults: { + additionalClasses: {}, + displayArea: 'outsideGroup', + displayAsLink: false, + elementTmpl: 'ui/form/element/button', + template: 'ui/form/components/button/simple' + }, + + /** + * Initializes component. + * + * @returns {Object} Chainable. + */ + initialize: function () { + return this._super() + ._setClasses(); + }, + + /** + * Performs configured actions + */ + action: function () { + this.actions.forEach(this.applyAction, this); + }, + + /** + * Apply action on target component, + * but previously create this component from template if it is not existed + * + * @param {Object} action - action configuration + */ + applyAction: function (action) { + var targetName = action.targetName, + params = action.params, + actionName = action.actionName, + target; + + if (!registry.has(targetName)) { + this.getFromTemplate(targetName); + } + target = registry.async(targetName); + + if (target && typeof target === 'function' && actionName) { + target(actionName, params); + } + }, + + /** + * Create target component from template + * + * @param {Object} targetName - name of component, + * that supposed to be a template and need to be initialized + */ + getFromTemplate: function (targetName) { + var parentName = targetName.split('.'), + index = parentName.pop(), + child; + + parentName = parentName.join('.'); + child = utils.template({ + parent: parentName, + name: index, + nodeTemplate: targetName + }); + layout([child]); + }, + + /** + * Extends 'additionalClasses' object. + * + * @returns {Object} Chainable. + */ + _setClasses: function () { + if (typeof this.additionalClasses === 'string') { + this.additionalClasses = this.additionalClasses + .trim() + .split(' ') + .reduce(function (classes, name) { + classes[name] = true; + + return classes; + }, {} + ); + } + + return this; + } + }); +}); diff --git a/app/code/Magento/Ui/view/base/web/js/lib/core/element/links.js b/app/code/Magento/Ui/view/base/web/js/lib/core/element/links.js index c769be3775f46ddba47d5d9110974fc2bd5782da..1ac9b45a46e86a9df232db8993932a886c3bcd8c 100644 --- a/app/code/Magento/Ui/view/base/web/js/lib/core/element/links.js +++ b/app/code/Magento/Ui/view/base/web/js/lib/core/element/links.js @@ -51,7 +51,7 @@ define([ } if (owner.component !== target.component) { - value = utils.copy(value); + value = data.inversionValue ? !utils.copy(value) : utils.copy(value); } component.set(property, value); @@ -149,6 +149,11 @@ define([ function transfer(owner, data) { var args = _.toArray(arguments); + if (data.target.substr(0,1) === '!') { + data.target = data.target.substr(1); + data.inversionValue = true; + } + if (owner.name === data.target) { args.unshift(owner); diff --git a/app/code/Magento/Ui/view/base/web/js/lib/knockout/bindings/outer_click.js b/app/code/Magento/Ui/view/base/web/js/lib/knockout/bindings/outer_click.js index 839a87481a38631267f295c9908abf2873d74f4d..7fa3ff22af8975b62d23b3f9c07ff3ab8d813c39 100644 --- a/app/code/Magento/Ui/view/base/web/js/lib/knockout/bindings/outer_click.js +++ b/app/code/Magento/Ui/view/base/web/js/lib/knockout/bindings/outer_click.js @@ -15,6 +15,30 @@ define([ onlyIfVisible: true }; + /** + * Checks if element sis visible. + * + * @param {Element} el + * @returns {Boolean} + */ + function isVisible(el) { + var style = window.getComputedStyle(el), + visibility = { + display: 'none', + visibility: 'hidden', + opacity: '0' + }, + visible = true; + + _.each(visibility, function (val, key) { + if (style[key] === val) { + visible = false; + } + }); + + return visible; + } + /** * Document click handler which in case if event target is not * a descendant of provided container element, @@ -33,7 +57,7 @@ define([ } if (config.onlyIfVisible) { - if (!_.isNull(container.offsetParent)) { + if (!_.isNull(container.offsetParent) && isVisible(container)) { callback(); } } else { diff --git a/app/code/Magento/Ui/view/base/web/js/modal/modal-component.js b/app/code/Magento/Ui/view/base/web/js/modal/modal-component.js new file mode 100644 index 0000000000000000000000000000000000000000..cccf95e00bf54f2a667e85fab4d5f12b435728a5 --- /dev/null +++ b/app/code/Magento/Ui/view/base/web/js/modal/modal-component.js @@ -0,0 +1,315 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +define([ + 'Magento_Ui/js/lib/view/utils/async', + 'uiCollection', + 'uiRegistry', + 'underscore', + './modal' +], function ($, Collection, registry, _) { + 'use strict'; + + return Collection.extend({ + defaults: { + template: 'ui/modal/modal-component', + options: { + title: '', + buttons: [], + keyEventHandlers: {} + }, + valid: true, + listens: { + state: 'onState' + }, + modalClass: 'modal-component' + }, + + /** + * Initializes component. + * + * @returns {Object} Chainable. + */ + initialize: function () { + this._super(); + _.bindAll(this, + 'initModal', + 'openModal', + 'closeModal', + 'toggleModal', + 'setPrevValues', + 'actionCancel', + 'validate'); + this.initializeContent(); + + return this; + }, + + /** + * Initializes modal configuration + * + * @returns {Object} Chainable. + */ + initConfig: function () { + return this._super() + .initSelector() + .initModalEvents(); + }, + + /** + * Configure modal selector + * + * @returns {Object} Chainable. + */ + initSelector: function () { + this.contentSelector = '.' + this.modalClass; + this.options.modalClass = this.name.replace(/\./g, '_'); + this.rootSelector = '.' + this.options.modalClass; + + return this; + }, + + /** + * Configure modal keyboard handlers + * and outer click + * + * @returns {Object} Chainable. + */ + initModalEvents: function () { + this.options.keyEventHandlers.escapeKey = this.options.outerClickHandler = this.actionCancel.bind(this); + + return this; + }, + + /** + * Initialize modal's content components + */ + initializeContent: function () { + $.async(this.contentSelector, this, this.initModal); + }, + + /** + * Init toolbar section so other components will be able to place something in it + */ + initToolbarSection: function () { + this.set('toolbarSection', this.modal.data('modal').modal.find('header').get(0)); + }, + + /** + * Initializes observable properties. + * + * @returns {Object} Chainable. + */ + initObservable: function () { + this._super(); + this.observe('state'); + + return this; + }, + + /** + * Wrap content in a modal of certain type + * + * @param {HTMLElement} element + * @returns {Object} Chainable. + */ + initModal: function (element) { + if (!this.modal) { + this.overrideModalButtonCallback(); + this.options.modalCloseBtnHandler = this.actionCancel; + this.modal = $(element).modal(this.options); + this.initToolbarSection(); + + if (this.waitCbk) { + this.waitCbk(); + this.waitCbk = null; + } + } + + return this; + }, + + /** + * Open modal + */ + openModal: function () { + if (this.modal) { + this.state(true); + } else { + this.waitCbk = this.openModal; + } + }, + + /** + * Close modal + */ + closeModal: function () { + if (this.modal) { + this.state(false); + } else { + this.waitCbk = this.closeModal; + } + }, + + /** + * Toggle modal + */ + toggleModal: function () { + if (this.modal) { + this.state(!this.state()); + } else { + this.waitCbk = this.toggleModal; + } + }, + + /** + * Wrap content in a modal of certain type + * + * @param {Boolean} state + */ + onState: function (state) { + if (state) { + this.modal.modal('openModal'); + this.applyData(); + } else { + this.modal.modal('closeModal'); + } + }, + + /** + * Validate everything validatable in modal + */ + validate: function (elem) { + if (typeof elem.validate === 'function') { + this.valid = this.valid & elem.validate().valid; + } else if (elem.elems) { + elem.elems().forEach(this.validate, this); + } + }, + + /** + * Reset data from provider + */ + resetData: function () { + this.elems().forEach(this.resetValue, this); + }, + + /** + * Update 'applied' property with data from modal content + */ + applyData: function () { + var applied = {}; + + this.elems().forEach(this.gatherValues.bind(this, applied), this); + this.applied = applied; + }, + + /** + * Gather values from modal content + * + * @param {Array} applied + * @param {HTMLElement} elem + */ + gatherValues: function (applied, elem) { + if (typeof elem.value === 'function') { + applied[elem.index] = elem.value(); + } else if (elem.elems) { + elem.elems().forEach(this.gatherValues.bind(this, applied), this); + } + }, + + /** + * Set to previous values from modal content + * + * @param {HTMLElement} elem + */ + setPrevValues: function (elem) { + if (typeof elem.value === 'function') { + this.modal.focus(); + elem.value(this.applied[elem.index]); + } else if (elem.elems) { + elem.elems().forEach(this.setPrevValues, this); + } + }, + + /** + * Triggers some method in every modal child elem, if this method is defined + * + * @param {Object} action - action configuration, + * must contain actionName and targetName and + * can contain params + */ + triggerAction: function (action) { + var targetName = action.targetName, + params = action.params, + actionName = action.actionName, + target; + + target = registry.async(targetName); + + if (target && typeof target === 'function' && actionName) { + target(actionName, params); + } + }, + + /** + * Override modal buttons callback placeholders with real callbacks + */ + overrideModalButtonCallback: function () { + var buttons = this.options.buttons; + + if (buttons && buttons.length) { + buttons.forEach(function (button) { + button.click = this.getButtonClickHandler(button.actions); + }, this); + } + }, + + /** + * Generate button click handler based on button's 'actions' configuration + */ + getButtonClickHandler: function (actionsConfig) { + var actions = actionsConfig.map( + function (actionConfig) { + if (_.isObject(actionConfig)) { + return this.triggerAction.bind(this, actionConfig); + } + + return this[actionConfig] ? this[actionConfig].bind(this) : function () {}; + }, this); + + return function () { + actions.forEach( + function (action) { + action(); + } + ); + }; + }, + + /** + * Cancels changes in modal: + * returning elems values to the previous state, + * and close modal + */ + actionCancel: function () { + this.elems().forEach(this.setPrevValues, this); + this.closeModal(); + }, + + /** + * Accept changes in modal by not preventing them. + * Can be extended by exporting 'gatherValues' result somewhere + */ + actionDone: function () { + this.valid = true; + this.elems().forEach(this.validate, this); + + if (this.valid) { + this.closeModal(); + } + } + }); +}); diff --git a/app/code/Magento/Ui/view/base/web/js/modal/modal.js b/app/code/Magento/Ui/view/base/web/js/modal/modal.js index 23011d607cdadc301ee6cf4cebeb148b400c0260..5dcfc53459baad6607edce1f13be49e708ead692 100644 --- a/app/code/Magento/Ui/view/base/web/js/modal/modal.js +++ b/app/code/Magento/Ui/view/base/web/js/modal/modal.js @@ -118,13 +118,14 @@ define([ 'closeModal' ); + _.extend(this.keyEventHandlers, this.options.keyEventHandlers); this.options.transitionEvent = transitionEvent; this._createWrapper(); this._renderModal(); this._createButtons(); $(this.options.trigger).on('click', _.bind(this.toggleModal, this)); this._on(this.modal.find(this.options.modalCloseBtn), { - 'click': this.closeModal + 'click': this.options.modalCloseBtnHandler ? this.options.modalCloseBtnHandler : this.closeModal }); this._on(this.element, { 'openModal': this.openModal, @@ -374,7 +375,8 @@ define([ * Creates overlay, append it to wrapper, set previous click event on overlay. */ _createOverlay: function () { - var events; + var events, + outerClickHandler = this.options.outerClickHandler || this.closeModal; this.overlay = $('.' + this.options.overlayClass); @@ -386,7 +388,7 @@ define([ } events = $._data(this.overlay.get(0), 'events'); events ? this.prevOverlayHandler = events.click[0].handler : false; - this.options.clickableOverlay ? this.overlay.unbind().on('click', this.closeModal) : false; + this.options.clickableOverlay ? this.overlay.unbind().on('click', outerClickHandler) : false; }, /** diff --git a/app/code/Magento/Ui/view/base/web/templates/form/components/button/simple.html b/app/code/Magento/Ui/view/base/web/templates/form/components/button/simple.html new file mode 100644 index 0000000000000000000000000000000000000000..d562e699c843a584fabd5f35905ca5e92ef8ad96 --- /dev/null +++ b/app/code/Magento/Ui/view/base/web/templates/form/components/button/simple.html @@ -0,0 +1,7 @@ +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<render args="elementTmpl"/> \ No newline at end of file diff --git a/app/code/Magento/Ui/view/base/web/templates/form/element/button.html b/app/code/Magento/Ui/view/base/web/templates/form/element/button.html new file mode 100644 index 0000000000000000000000000000000000000000..8f337ce7acb966b57b511b1535ceedb6117cdc03 --- /dev/null +++ b/app/code/Magento/Ui/view/base/web/templates/form/element/button.html @@ -0,0 +1,14 @@ +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<button type="button" + css=" + 'action-advanced': $data.displayAsLink, + 'action-secondary': !$data.displayAsLink + " + click="action" + text="title"> +</button> \ No newline at end of file diff --git a/app/code/Magento/Ui/view/base/web/templates/modal/modal-component.html b/app/code/Magento/Ui/view/base/web/templates/modal/modal-component.html new file mode 100644 index 0000000000000000000000000000000000000000..e39c27e0741232496319e1385a667b181ee623f7 --- /dev/null +++ b/app/code/Magento/Ui/view/base/web/templates/modal/modal-component.html @@ -0,0 +1,12 @@ +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<div data-bind="css: modalClass"> + <!-- ko foreach: { data: elems, as: 'element' } --> + <!-- ko template: element.getTemplate() --><!-- /ko --> + <!-- /ko --> +</div> \ No newline at end of file diff --git a/app/code/Magento/UrlRewrite/view/adminhtml/templates/categories.phtml b/app/code/Magento/UrlRewrite/view/adminhtml/templates/categories.phtml index 5c27c009b445158c3714fb1464a0c68234537211..420638d5a8ea77aa27b603ba4f8fcdc9d6f4db76 100644 --- a/app/code/Magento/UrlRewrite/view/adminhtml/templates/categories.phtml +++ b/app/code/Magento/UrlRewrite/view/adminhtml/templates/categories.phtml @@ -13,14 +13,14 @@ <div class="content" style="clear: both;"> <input type="hidden" name="categories" id="product_categories" value="" /> <?php if ($block->getRoot()): ?> - <div data-mage-init='<?php + <div data-mage-init="<?php echo $block->escapeHtml($this->helper('Magento\Framework\Json\Helper\Data')->jsonEncode([ 'categoryTree' => [ 'data' => $block->getTreeArray(null), 'url' => $block->getLoadTreeUrl(), ], ])); - ?>' class="jstree-default"></div> + ?>" class="jstree-default"></div> <?php endif; ?> </div> </fieldset> diff --git a/app/code/Magento/Widget/view/adminhtml/templates/catalog/category/widget/tree.phtml b/app/code/Magento/Widget/view/adminhtml/templates/catalog/category/widget/tree.phtml index 135880f5f314214efdc4d95540f489a5fc7bd8fe..89d2b75a3b882322a91f953208242673130ae5b9 100644 --- a/app/code/Magento/Widget/view/adminhtml/templates/catalog/category/widget/tree.phtml +++ b/app/code/Magento/Widget/view/adminhtml/templates/catalog/category/widget/tree.phtml @@ -10,7 +10,7 @@ <?php $_divId = 'tree' . $block->getId() ?> <div id="<?php /* @escapeNotVerified */ echo $_divId ?>" class="tree"></div> -<script id="ie-deferred-loader" defer="defer" src=""></script> +<script id="ie-deferred-loader" defer="defer" src="//:"></script> <script> require(['jquery', "prototype", "extjs/ext-tree-checkbox"], function(jQuery){ diff --git a/app/code/Magento/Widget/view/adminhtml/templates/instance/edit/layout.phtml b/app/code/Magento/Widget/view/adminhtml/templates/instance/edit/layout.phtml index 6831ca32a007b1c5abe9f67b322e76fe5ee38749..a98b8df1fd5deb0e3b50ee395f4a9102cca68083 100644 --- a/app/code/Magento/Widget/view/adminhtml/templates/instance/edit/layout.phtml +++ b/app/code/Magento/Widget/view/adminhtml/templates/instance/edit/layout.phtml @@ -15,7 +15,7 @@ <div class="actions"><?php echo $block->getAddLayoutButtonHtml() ?></div> </div> </fieldset> -<script id="ie-deferred-loader" defer="defer" src=""></script> +<script id="ie-deferred-loader" defer="defer" src="//:"></script> <script> require([ 'jquery', diff --git a/app/etc/di.xml b/app/etc/di.xml index f19b5e2aa44af740cbf47989ab09d56a3bc45296..c742aa25af54173424754282c1be8337b2defd7b 100755 --- a/app/etc/di.xml +++ b/app/etc/di.xml @@ -142,6 +142,8 @@ <preference for="Magento\Framework\Stdlib\DateTime\DateTimeFormatterInterface" type="Magento\Framework\Stdlib\DateTime\DateTimeFormatter"/> <preference for="Magento\Framework\Api\Search\SearchInterface" type="Magento\Framework\Search\Search"/> <preference for="Magento\Framework\View\Design\FileResolution\Fallback\ResolverInterface" type="Magento\Framework\View\Design\FileResolution\Fallback\Resolver\Simple" /> + <preference for="Cm\RedisSession\Handler\ConfigInterface" type="Magento\Framework\Session\SaveHandler\Redis\Config"/> + <preference for="Cm\RedisSession\Handler\LoggerInterface" type="Magento\Framework\Session\SaveHandler\Redis\Logger"/> <type name="Magento\Framework\Model\ResourceModel\Db\TransactionManager" shared="false" /> <type name="Magento\Framework\Logger\Handler\Base"> <arguments> @@ -187,9 +189,16 @@ <arguments> <argument name="handlers" xsi:type="array"> <item name="db" xsi:type="string">Magento\Framework\Session\SaveHandler\DbTable</item> + <item name="redis" xsi:type="string">Magento\Framework\Session\SaveHandler\Redis</item> </argument> </arguments> </type> + <type name="Magento\Framework\Session\SaveHandler\Redis"> + <arguments> + <argument name="config" xsi:type="object">Cm\RedisSession\Handler\ConfigInterface</argument> + <argument name="logger" xsi:type="object">Cm\RedisSession\Handler\LoggerInterface</argument> + </arguments> + </type> <virtualType name="interceptionConfigScope" type="Magento\Framework\Config\Scope"> <arguments> <argument name="defaultScope" xsi:type="string">global</argument> diff --git a/composer.json b/composer.json index 2690ac011a4658852e9dff9a592a5aa9524574fe..6de9572c2a9586377f036c0f813c0801f51f0b3c 100644 --- a/composer.json +++ b/composer.json @@ -32,6 +32,8 @@ "zendframework/zend-log": "~2.4.6", "zendframework/zend-http": "~2.4.6", "magento/zendframework1": "1.12.16", + "colinmollenhour/credis": "1.6", + "colinmollenhour/php-redis-session-abstract": "1.0", "composer/composer": "1.0.0-alpha10", "monolog/monolog": "1.16.0", "oyejorge/less.php": "1.7.0.3", @@ -183,7 +185,6 @@ "magento/framework": "100.0.2", "trentrichardson/jquery-timepicker-addon": "1.4.3", "colinmollenhour/cache-backend-redis": "1.8", - "colinmollenhour/credis": "1.5", "components/jquery": "1.11.0", "blueimp/jquery-file-upload": "5.6.14", "components/jqueryui": "1.10.4", @@ -194,7 +195,6 @@ "component_paths": { "trentrichardson/jquery-timepicker-addon": "lib/web/jquery/jquery-ui-timepicker-addon.js", "colinmollenhour/cache-backend-redis": "lib/internal/Cm/Cache/Backend/Redis.php", - "colinmollenhour/credis": "lib/internal/Credis", "components/jquery": [ "lib/web/jquery.js", "lib/web/jquery/jquery.min.js", diff --git a/composer.lock b/composer.lock index 7fefee4db023190b62542ce48d8316a78d0856cc..a8c2a9acb5732af76eb4153a39bf27b61eb750f8 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "80d81327a228d96ed4512c92e09d5b02", - "content-hash": "7a457b69136c2954644691bd92ca7cc6", + "hash": "14cde9a911c97dfb8b8d65aa2fc37a9f", + "content-hash": "3ca6f21142f50665ed50595bfb546c41", "packages": [ { "name": "braintree/braintree_php", @@ -54,6 +54,83 @@ "description": "Braintree PHP Client Library", "time": "2015-11-19 19:14:47" }, + { + "name": "colinmollenhour/credis", + "version": "1.6", + "source": { + "type": "git", + "url": "https://github.com/colinmollenhour/credis.git", + "reference": "409edfd0ea81f5cb74afbdb86df54890c207b5e4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/colinmollenhour/credis/zipball/409edfd0ea81f5cb74afbdb86df54890c207b5e4", + "reference": "409edfd0ea81f5cb74afbdb86df54890c207b5e4", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "Client.php", + "Cluster.php", + "Sentinel.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Colin Mollenhour", + "email": "colin@mollenhour.com" + } + ], + "description": "Credis is a lightweight interface to the Redis key-value store which wraps the phpredis library when available for better performance.", + "homepage": "https://github.com/colinmollenhour/credis", + "time": "2015-11-28 01:20:04" + }, + { + "name": "colinmollenhour/php-redis-session-abstract", + "version": "v1.0", + "source": { + "type": "git", + "url": "https://github.com/colinmollenhour/php-redis-session-abstract.git", + "reference": "1308ddc08e2adbe303f7f8b8ead9beb5f2f2adf9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/colinmollenhour/php-redis-session-abstract/zipball/1308ddc08e2adbe303f7f8b8ead9beb5f2f2adf9", + "reference": "1308ddc08e2adbe303f7f8b8ead9beb5f2f2adf9", + "shasum": "" + }, + "require": { + "colinmollenhour/credis": "1.6", + "magento/zendframework1": "1.12.16", + "php": "~5.5.0|~5.6.0|~7.0.0" + }, + "type": "library", + "autoload": { + "psr-0": { + "Cm\\RedisSession\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Colin Mollenhour" + } + ], + "description": "A Redis-based session handler with optimistic locking", + "homepage": "https://github.com/colinmollenhour/php-redis-session-abstract", + "time": "2016-01-14 16:04:27" + }, { "name": "composer/composer", "version": "1.0.0-alpha10", @@ -720,7 +797,7 @@ }, { "name": "symfony/console", - "version": "v2.6.12", + "version": "v2.6.13", "target-dir": "Symfony/Component/Console", "source": { "type": "git", @@ -778,16 +855,16 @@ }, { "name": "symfony/event-dispatcher", - "version": "v2.8.1", + "version": "v2.8.2", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "a5eb815363c0388e83247e7e9853e5dbc14999cc" + "reference": "ee278f7c851533e58ca307f66305ccb9188aceda" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/a5eb815363c0388e83247e7e9853e5dbc14999cc", - "reference": "a5eb815363c0388e83247e7e9853e5dbc14999cc", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/ee278f7c851533e58ca307f66305ccb9188aceda", + "reference": "ee278f7c851533e58ca307f66305ccb9188aceda", "shasum": "" }, "require": { @@ -834,20 +911,20 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "time": "2015-10-30 20:15:42" + "time": "2016-01-13 10:28:07" }, { "name": "symfony/finder", - "version": "v2.8.1", + "version": "v2.8.2", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "dd41ae57f4f737be271d944a0cc5f5f21203a7c6" + "reference": "c90fabdd97e431ee19b6383999cf35334dff27da" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/dd41ae57f4f737be271d944a0cc5f5f21203a7c6", - "reference": "dd41ae57f4f737be271d944a0cc5f5f21203a7c6", + "url": "https://api.github.com/repos/symfony/finder/zipball/c90fabdd97e431ee19b6383999cf35334dff27da", + "reference": "c90fabdd97e431ee19b6383999cf35334dff27da", "shasum": "" }, "require": { @@ -883,20 +960,20 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2015-12-05 11:09:21" + "time": "2016-01-14 08:26:52" }, { "name": "symfony/process", - "version": "v2.8.1", + "version": "v2.8.2", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "62c254438b5040bc2217156e1570cf2206e8540c" + "reference": "6f1979c3b0f4c22c77a8a8971afaa7dd07f082ac" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/62c254438b5040bc2217156e1570cf2206e8540c", - "reference": "62c254438b5040bc2217156e1570cf2206e8540c", + "url": "https://api.github.com/repos/symfony/process/zipball/6f1979c3b0f4c22c77a8a8971afaa7dd07f082ac", + "reference": "6f1979c3b0f4c22c77a8a8971afaa7dd07f082ac", "shasum": "" }, "require": { @@ -932,7 +1009,7 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2015-12-23 11:03:46" + "time": "2016-01-06 09:59:23" }, { "name": "tedivm/jshrink", @@ -2581,16 +2658,16 @@ }, { "name": "fabpot/php-cs-fixer", - "version": "v1.11", + "version": "v1.11.1", "source": { "type": "git", "url": "https://github.com/FriendsOfPHP/PHP-CS-Fixer.git", - "reference": "bd3ec2c2b774e0e127ac2c737ec646d9cf2f9eef" + "reference": "2c9f8298181f059c5077abda78019b9a0c9a7cc0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/bd3ec2c2b774e0e127ac2c737ec646d9cf2f9eef", - "reference": "bd3ec2c2b774e0e127ac2c737ec646d9cf2f9eef", + "url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/2c9f8298181f059c5077abda78019b9a0c9a7cc0", + "reference": "2c9f8298181f059c5077abda78019b9a0c9a7cc0", "shasum": "" }, "require": { @@ -2631,7 +2708,7 @@ } ], "description": "A tool to automatically fix PHP code style", - "time": "2015-12-01 22:34:33" + "time": "2016-01-20 19:00:28" }, { "name": "league/climate", @@ -3672,16 +3749,16 @@ }, { "name": "symfony/config", - "version": "v2.8.1", + "version": "v2.8.2", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "17d4b2e64ce1c6ba7caa040f14469b3c44d7f7d2" + "reference": "41ee6c70758f40fa1dbf90d019ae0a66c4a09e74" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/17d4b2e64ce1c6ba7caa040f14469b3c44d7f7d2", - "reference": "17d4b2e64ce1c6ba7caa040f14469b3c44d7f7d2", + "url": "https://api.github.com/repos/symfony/config/zipball/41ee6c70758f40fa1dbf90d019ae0a66c4a09e74", + "reference": "41ee6c70758f40fa1dbf90d019ae0a66c4a09e74", "shasum": "" }, "require": { @@ -3718,20 +3795,20 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", - "time": "2015-12-26 13:37:56" + "time": "2016-01-03 15:33:41" }, { "name": "symfony/dependency-injection", - "version": "v2.8.1", + "version": "v2.8.2", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "c5086d186f538c2711b9af6f727be7b0446979cd" + "reference": "ba94a914e244e0d05f0aaef460d5558d5541d2b1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/c5086d186f538c2711b9af6f727be7b0446979cd", - "reference": "c5086d186f538c2711b9af6f727be7b0446979cd", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/ba94a914e244e0d05f0aaef460d5558d5541d2b1", + "reference": "ba94a914e244e0d05f0aaef460d5558d5541d2b1", "shasum": "" }, "require": { @@ -3780,20 +3857,20 @@ ], "description": "Symfony DependencyInjection Component", "homepage": "https://symfony.com", - "time": "2015-12-26 13:37:56" + "time": "2016-01-12 17:46:01" }, { "name": "symfony/filesystem", - "version": "v2.8.1", + "version": "v2.8.2", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "a7ad724530a764d70c168d321ac226ba3d2f10fc" + "reference": "637b64d0ee10f44ae98dbad651b1ecdf35a11e8c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/a7ad724530a764d70c168d321ac226ba3d2f10fc", - "reference": "a7ad724530a764d70c168d321ac226ba3d2f10fc", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/637b64d0ee10f44ae98dbad651b1ecdf35a11e8c", + "reference": "637b64d0ee10f44ae98dbad651b1ecdf35a11e8c", "shasum": "" }, "require": { @@ -3829,7 +3906,7 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2015-12-22 10:25:57" + "time": "2016-01-13 10:28:07" }, { "name": "symfony/stopwatch", @@ -3882,16 +3959,16 @@ }, { "name": "symfony/yaml", - "version": "v2.8.1", + "version": "v2.8.2", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "ac84cbb98b68a6abbc9f5149eb96ccc7b07b8966" + "reference": "34c8a4b51e751e7ea869b8262f883d008a2b81b8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/ac84cbb98b68a6abbc9f5149eb96ccc7b07b8966", - "reference": "ac84cbb98b68a6abbc9f5149eb96ccc7b07b8966", + "url": "https://api.github.com/repos/symfony/yaml/zipball/34c8a4b51e751e7ea869b8262f883d008a2b81b8", + "reference": "34c8a4b51e751e7ea869b8262f883d008a2b81b8", "shasum": "" }, "require": { @@ -3927,7 +4004,7 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2015-12-26 13:37:56" + "time": "2016-01-13 10:28:07" } ], "aliases": [], diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Block/System/Config/Form.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Block/System/Config/Form.php index 86ae1d8d66a067591d0fae2bed7b35c58f068663..35250af124192cfa13a2222eae81f2c90f141030 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Block/System/Config/Form.php +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Block/System/Config/Form.php @@ -1,53 +1,130 @@ <?php /** - * Store configuration edit form + * Store configuration edit form. * * Copyright © 2015 Magento. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Backend\Test\Block\System\Config; -use Magento\Mtf\Block\Block; use Magento\Mtf\Factory\Factory; +use Magento\Mtf\Block\BlockFactory; +use Magento\Mtf\Block\Block; +use Magento\Mtf\Client\ElementInterface; +use Magento\Mtf\Client\BrowserInterface; use Magento\Mtf\Client\Locator; +/** + * Class Form. + */ class Form extends Block { /** - * Group block + * Group block selector. + * + * @var string + */ + protected $groupBlock = '.section-config.active #%s_%s'; + + /** + * Group block link selector. * * @var string */ - protected $groupBlock = '//legend[contains(text(), "%s")]/../..'; + protected $groupBlockLink = '#%s_%s-head'; /** - * Save button + * Save button selector. * * @var string */ - protected $saveButton = '//button[@data-ui-id="system-config-edit-save-button"]'; + protected $saveButton = '#save'; /** - * Retrieve store configuration form group + * Tab content readiness. * - * @param string $name + * @var string + */ + protected $tabReadiness = '.admin__page-nav-item._active._loading'; + + /** + * Url associated with the form. + * + * @var string + */ + protected $baseUrl; + + /** + * @constructor + * @param ElementInterface $element + * @param BlockFactory $blockFactory + * @param BrowserInterface $browser + * @param array $config + */ + public function __construct( + ElementInterface $element, + BlockFactory $blockFactory, + BrowserInterface $browser, + array $config = [] + ) { + parent::__construct($element, $blockFactory, $browser, $config); + $this->baseUrl = $this->browser->getUrl(); + if (substr($this->baseUrl, -1) !== '/') { + $this->baseUrl = $this->baseUrl . '/'; + } + } + + /** + * Obtain store configuration form group. + * + * @param string $tabName + * @param string $groupName * @return Form\Group */ - public function getGroup($name) + public function getGroup($tabName, $groupName) { - $blockFactory = Factory::getBlockFactory(); - $element = $this->_rootElement->find( - sprintf($this->groupBlock, $name), - Locator::SELECTOR_XPATH + $tabUrl = $this->baseUrl . 'section/' . $tabName; + if ($this->getBrowserUrl() !== $tabUrl) { + $this->browser->open($tabUrl); + } + $this->waitForElementNotVisible($this->tabReadiness); + + $groupElement = $this->_rootElement->find( + sprintf($this->groupBlock, $tabName, $groupName), + Locator::SELECTOR_CSS ); - return $blockFactory->getMagentoBackendSystemConfigFormGroup($element); + + if (!$groupElement->isVisible()) { + $this->_rootElement->find( + sprintf($this->groupBlockLink, $tabName, $groupName), + Locator::SELECTOR_CSS + )->click(); + + $this->waitForElementNotVisible($this->tabReadiness); + + $groupElement = $this->_rootElement->find( + sprintf($this->groupBlock, $tabName, $groupName), + Locator::SELECTOR_CSS + ); + } + + $blockFactory = Factory::getBlockFactory(); + return $blockFactory->getMagentoBackendSystemConfigFormGroup($groupElement); + } + + /** + * Retrieve url associated with the form. + */ + public function getBrowserUrl() + { + return $this->browser->getUrl(); } /** - * Save store configuration + * Save store configuration. */ public function save() { - $this->_rootElement->find($this->saveButton, Locator::SELECTOR_XPATH)->click(); + $this->_rootElement->find($this->saveButton, Locator::SELECTOR_CSS)->click(); } } diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Block/System/Config/Form/Group.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Block/System/Config/Form/Group.php index 09123d09767bf838415192989cd1f5f06732360b..efaf58fed1584fc63f6b84fd79fe2bffceb7619f 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Block/System/Config/Form/Group.php +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Block/System/Config/Form/Group.php @@ -1,6 +1,6 @@ <?php /** - * Store configuration group + * Store configuration group. * * Copyright © 2015 Magento. All rights reserved. * See COPYING.txt for license details. @@ -12,72 +12,62 @@ use Magento\Mtf\Client\Locator; use Magento\Mtf\Block\Form; /** - * Class Group + * Class Group. */ class Group extends Form { /** - * Fieldset selector + * Fieldset selector. * * @var string */ - protected $fieldset = 'fieldset'; + protected $fieldset = '#%s_%s'; /** - * Toggle link + * Field selector. * * @var string */ - protected $toogleLink = '.entry-edit-head a'; + protected $field = '#%s_%s_%s'; /** - * Field element selector + * Default checkbox selector. * * @var string */ - protected $element = '//*[@data-ui-id="%s"]'; + protected $defaultCheckbox = '#%s_%s_%s_inherit'; /** - * Default checkbox selector + * Set store configuration value by element data-ui-id. * - * @var string - */ - protected $defaultCheckbox = '//*[@data-ui-id="%s"]/../../*[@class="use-default"]/input'; - - /** - * Open group fieldset - */ - public function open() - { - if (!$this->_rootElement->find($this->fieldset)->isVisible()) { - $this->_rootElement->find($this->toogleLink)->click(); - } - } - - /** - * Set store configuration value by element data-ui-id - * - * @param string $field + * @param string $tabName + * @param string $groupName + * @param string $fieldName * @param mixed $value */ - public function setValue($field, $value) + public function setValue($tabName, $groupName, $fieldName, $value) { $input = null; - $fieldParts = explode('-', $field); - if (in_array($fieldParts[0], ['select', 'checkbox'])) { - $input = $fieldParts[0]; + $attribute = $this->_rootElement->find( + sprintf($this->field, $tabName, $groupName, $fieldName), + Locator::SELECTOR_CSS + )->getAttribute('data-ui-id'); + + $parts = explode('-', $attribute, 2); + if (in_array($parts[0], ['select', 'text', 'checkbox'])) { + $input = $parts[0]; } $element = $this->_rootElement->find( - sprintf($this->element, $field), - Locator::SELECTOR_XPATH, + sprintf($this->field, $tabName, $groupName, $fieldName), + Locator::SELECTOR_CSS, $input ); if ($element->isDisabled()) { $checkbox = $this->_rootElement->find( - sprintf($this->defaultCheckbox, $field), - Locator::SELECTOR_XPATH, + sprintf($this->defaultCheckbox, $tabName, $groupName, $fieldName), + Locator::SELECTOR_CSS, 'checkbox' ); $checkbox->setValue('No'); @@ -85,4 +75,20 @@ class Group extends Form $element->setValue($value); } + + /** + * Check if a field is visible in a given group. + * + * @param string $tabName + * @param string $groupName + * @param string $fieldName + * @return bool + */ + public function isFieldVisible($tabName, $groupName, $fieldName) + { + $this->_rootElement->find( + sprintf($this->field, $tabName, $groupName, $fieldName), + Locator::SELECTOR_CSS + )->isVisible(); + } } diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertHttpsHeaderOptionsAvailable.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertHttpsHeaderOptionsAvailable.php new file mode 100644 index 0000000000000000000000000000000000000000..fc670da5b445fe8713004605b92f62c5faac6f59 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertHttpsHeaderOptionsAvailable.php @@ -0,0 +1,77 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Backend\Test\Constraint; + +use Magento\Mtf\Constraint\AbstractConstraint; +use Magento\Backend\Test\Page\Adminhtml\SystemConfigEdit; +use Magento\Config\Test\Fixture\ConfigData; + +/** + * Assert that https header options are available. + */ +class AssertHttpsHeaderOptionsAvailable extends AbstractConstraint +{ + /** + * Assert that https header options are available. + * + * @param SystemConfigEdit $systemConfigEdit + * @param ConfigData $hsts + * @param ConfigData $upgradeInsecure + * @return void + */ + public function processAssert( + SystemConfigEdit $systemConfigEdit, + ConfigData $hsts, + ConfigData $upgradeInsecure + ) { + $this->verifyConfiguration($systemConfigEdit, $hsts); + $this->verifyConfiguration($systemConfigEdit, $upgradeInsecure); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'HTTPS headers configuration verification successfully.'; + } + + /** + * Verify configurations. + * + * @param SystemConfigEdit $systemConfigEdit + * @param ConfigData $config + * @return void + */ + private function verifyConfiguration(SystemConfigEdit $systemConfigEdit, ConfigData $config) + { + $section = $config->getSection(); + $keys = array_keys($section); + foreach ($keys as $key) { + $parts = explode('/', $key, 3); + $tabName = $parts[0]; + $groupName = $parts[1]; + $fieldName = $parts[2]; + try { + $group = $systemConfigEdit->getForm()->getGroup($tabName, $groupName); + $group->setValue($tabName, $groupName, $fieldName, 'Yes'); + $group->setValue($tabName, $groupName, $fieldName, 'No'); + \PHPUnit_Framework_Assert::assertTrue( + true, + $fieldName . " configuration is enabled with options Yes & No." + ); + } catch (\PHPUnit_Extensions_Selenium2TestCase_WebDriverException $e) { + \PHPUnit_Framework_Assert::assertFalse( + true, + $fieldName . " configuration is not enabled with options Yes & No." + ); + } + } + } +} diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertHttpsHeaderOptionsNotAvailable.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertHttpsHeaderOptionsNotAvailable.php new file mode 100644 index 0000000000000000000000000000000000000000..e1c92159979006779b74d529fcb6e90e61138327 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertHttpsHeaderOptionsNotAvailable.php @@ -0,0 +1,71 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Backend\Test\Constraint; + +use Magento\Mtf\Constraint\AbstractConstraint; +use Magento\Backend\Test\Page\Adminhtml\SystemConfigEdit; +use Magento\Config\Test\Fixture\ConfigData; + +/** + * Assert that https header options are not available. + */ +class AssertHttpsHeaderOptionsNotAvailable extends AbstractConstraint +{ + /** + * Assert that https header options are available. + * + * @param SystemConfigEdit $systemConfigEdit + * @param ConfigData $hsts + * @param ConfigData $upgradeInsecure + * @return void + */ + public function processAssert( + SystemConfigEdit $systemConfigEdit, + ConfigData $hsts, + ConfigData $upgradeInsecure + ) { + $this->verifyConfiguration($systemConfigEdit, $hsts); + $this->verifyConfiguration($systemConfigEdit, $upgradeInsecure); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'HTTPS headers not visible verification successfully.'; + } + + /** + * Verify configurations. + * + * @param SystemConfigEdit $systemConfigEdit + * @param ConfigData $config + * @return void + */ + private function verifyConfiguration( + SystemConfigEdit $systemConfigEdit, + ConfigData $config + ) { + $section = $config->getSection(); + $keys = array_keys($section); + foreach ($keys as $key) { + $parts = explode('/', $key, 3); + $tabName = $parts[0]; + $groupName = $parts[1]; + $fieldName = $parts[2]; + $isVisible = $systemConfigEdit->getForm()->getGroup($tabName, $groupName) + ->isFieldVisible($tabName, $groupName, $fieldName); + \PHPUnit_Framework_Assert::assertTrue( + !$isVisible, + $fieldName . " configuration is not visible." + ); + } + } +} diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertStoreCanBeLocalized.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertStoreCanBeLocalized.php index fd241121f62fc88eaa86debe9df1aa86242f53b0..97d98e8c332896edf8c74df3260c7bd2311c4c71 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertStoreCanBeLocalized.php +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertStoreCanBeLocalized.php @@ -39,9 +39,8 @@ class AssertStoreCanBeLocalized extends AbstractConstraint $systemConfig->open(); $systemConfig->getPageActions()->selectStore($store->getGroupId() . "/" . $store->getName()); $systemConfig->getModalBlock()->acceptAlert(); - $configGroup = $systemConfig->getForm()->getGroup('Locale Options'); - $configGroup->open(); - $configGroup->setValue('select-groups-locale-fields-code-value', $locale); + $configGroup = $systemConfig->getForm()->getGroup('general', 'locale', 'code'); + $configGroup->setValue('general', 'locale', 'code', $locale); $systemConfig->getPageActions()->save(); $systemConfig->getMessagesBlock()->waitSuccessMessage(); diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/SystemConfigEdit.xml b/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/SystemConfigEdit.xml new file mode 100644 index 0000000000000000000000000000000000000000..2d9ad23671175d8ce9d2d6092cafc783fc4425c4 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/SystemConfigEdit.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + --> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../vendor/magento/mtf/etc/pages.xsd"> + <page name="SystemConfigEdit" area="Adminhtml" mca="admin/system_config/edit" module="Magento_Backend"> + <block name="pageActions" class="Magento\Backend\Test\Block\System\Config\PageActions" locator=".page-main-actions" strategy="css selector"/> + <block name="form" class="Magento\Backend\Test\Block\System\Config\Form" locator="#config-edit-form" strategy="css selector"/> + <block name="messagesBlock" class="Magento\Backend\Test\Block\Messages" locator="#messages" strategy="css selector"/> + <block name="modalBlock" class="Magento\Ui\Test\Block\Adminhtml\Modal" locator="._show[data-role=modal]" strategy="css selector"/> + </page> +</config> diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Repository/ConfigData.xml b/dev/tests/functional/tests/app/Magento/Backend/Test/Repository/ConfigData.xml index 107555040bc1dd643b556b0bae34f3b4fe9cd9b7..9ac49e41ebb6f8781f980ce03e4d8d275a7402c8 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Repository/ConfigData.xml +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Repository/ConfigData.xml @@ -132,5 +132,50 @@ <item name="value" xsi:type="number">0</item> </field> </dataset> + + <dataset name="enable_https_frontend_admin"> + <field name="web/secure/use_in_frontend" xsi:type="array"> + <item name="scope" xsi:type="string">default</item> + <item name="scope_id" xsi:type="number">0</item> + <item name="label" xsi:type="string">Yes</item> + <item name="value" xsi:type="number">1</item> + </field> + <field name="web/secure/use_in_adminhtml" xsi:type="array"> + <item name="scope" xsi:type="string">default</item> + <item name="scope_id" xsi:type="number">0</item> + <item name="label" xsi:type="string">Yes</item> + <item name="value" xsi:type="number">1</item> + </field> + </dataset> + <dataset name="enable_hsts"> + <field name="web/secure/enable_hsts" xsi:type="array"> + <item name="scope" xsi:type="string">default</item> + <item name="scope_id" xsi:type="number">0</item> + <item name="label" xsi:type="string">Yes</item> + <item name="value" xsi:type="number">1</item> + </field> + </dataset> + <dataset name="enable_upgrade_insecure"> + <field name="web/secure/enable_upgrade_insecure" xsi:type="array"> + <item name="scope" xsi:type="string">default</item> + <item name="scope_id" xsi:type="number">0</item> + <item name="label" xsi:type="string">Yes</item> + <item name="value" xsi:type="number">1</item> + </field> + </dataset> + <dataset name="enable_https_frontend_only"> + <field name="web/secure/use_in_frontend" xsi:type="array"> + <item name="scope" xsi:type="string">default</item> + <item name="scope_id" xsi:type="number">0</item> + <item name="label" xsi:type="string">Yes</item> + <item name="value" xsi:type="number">1</item> + </field> + <field name="web/secure/use_in_adminhtml" xsi:type="array"> + <item name="scope" xsi:type="string">default</item> + <item name="scope_id" xsi:type="number">0</item> + <item name="label" xsi:type="string">No</item> + <item name="value" xsi:type="number">0</item> + </field> + </dataset> </repository> </config> diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/HttpsHeadersDisableTest.php b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/HttpsHeadersDisableTest.php new file mode 100644 index 0000000000000000000000000000000000000000..0a296699acb7e5c2b49b6030fbf577dacdff152f --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/HttpsHeadersDisableTest.php @@ -0,0 +1,52 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Backend\Test\TestCase; + +use Magento\Backend\Test\Page\Adminhtml\SystemConfigEdit; +use Magento\Config\Test\Fixture\ConfigData; +use Magento\Mtf\TestCase\Injectable; + +/** + * Steps: + * + * 1. Login to backend. + * 2. Go to Stores -> Configuration -> General -> Web. + * 3. Set "Use Secure URLs on Storefront" to Yes. + * 4. Set "Use Secure URLs in Admin" to No. + * 5. Perform asserts. + * + * @ZephyrId MAGETWO-46903 + */ +class HttpsHeadersDisableTest extends Injectable +{ + /* tags */ + const MVP = 'no'; + const DOMAIN = 'PS'; + /* end tags */ + + /** + * Open backend system config and set configuration values. + * + * @param SystemConfigEdit $systemConfigEdit + * @param ConfigData $httpsConfig + * @return void + */ + public function test(SystemConfigEdit $systemConfigEdit, ConfigData $httpsConfig) + { + $systemConfigEdit->open(); + $section = $httpsConfig->getSection(); + $keys = array_keys($section); + foreach ($keys as $key) { + $parts = explode('/', $key, 3); + $tabName = $parts[0]; + $groupName = $parts[1]; + $fieldName = $parts[2]; + $systemConfigEdit->getForm()->getGroup($tabName, $groupName) + ->setValue($tabName, $groupName, $fieldName, $section[$key]['label']); + } + } +} diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/HttpsHeadersDisableTest.xml b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/HttpsHeadersDisableTest.xml new file mode 100644 index 0000000000000000000000000000000000000000..b043ed89adcc317dbde4aaef113d27f29e0b19d8 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/HttpsHeadersDisableTest.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + --> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/variations.xsd"> + <testCase name="Magento\Backend\Test\TestCase\HttpsHeadersDisableTest" summary="HTTPS header options" ticketId="MAGETWO-46903"> + <variation name="DisableHttpsHeaderOptions" summary="Disable HTTPS header options" ticketId="MAGETWO-46903"> + <data name="httpsConfig/dataset" xsi:type="string">enable_https_frontend_only</data> + <data name="hsts/dataset" xsi:type="string">enable_hsts</data> + <data name="upgradeInsecure/dataset" xsi:type="string">enable_upgrade_insecure</data> + <constraint name="Magento\Backend\Test\Constraint\AssertHttpsHeaderOptionsNotAvailable"/> + </variation> + </testCase> +</config> + diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/HttpsHeadersEnableTest.php b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/HttpsHeadersEnableTest.php new file mode 100644 index 0000000000000000000000000000000000000000..f6269a49a212f856b555b4cd44c1d11431ad0b4f --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/HttpsHeadersEnableTest.php @@ -0,0 +1,52 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Backend\Test\TestCase; + +use Magento\Backend\Test\Page\Adminhtml\SystemConfigEdit; +use Magento\Config\Test\Fixture\ConfigData; +use Magento\Mtf\TestCase\Injectable; + +/** + * Steps: + * + * 1. Login to backend. + * 2. Go to Stores -> Configuration -> General -> Web. + * 3. Set "Use Secure URLs on Storefront" to Yes. + * 4. Set "Use Secure URLs in Admin" to Yes. + * 5. Perform asserts. + * + * @ZephyrId MAGETWO-46903 + */ +class HttpsHeadersEnableTest extends Injectable +{ + /* tags */ + const MVP = 'no'; + const DOMAIN = 'PS'; + /* end tags */ + + /** + * Open backend system config and set configuration values. + * + * @param SystemConfigEdit $systemConfigEdit + * @param ConfigData $httpsConfig + * @return void + */ + public function test(SystemConfigEdit $systemConfigEdit, ConfigData $httpsConfig) + { + $systemConfigEdit->open(); + $section = $httpsConfig->getSection(); + $keys = array_keys($section); + foreach ($keys as $key) { + $parts = explode('/', $key, 3); + $tabName = $parts[0]; + $groupName = $parts[1]; + $fieldName = $parts[2]; + $systemConfigEdit->getForm()->getGroup($tabName, $groupName) + ->setValue($tabName, $groupName, $fieldName, $section[$key]['label']); + } + } +} diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/HttpsHeadersEnableTest.xml b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/HttpsHeadersEnableTest.xml new file mode 100644 index 0000000000000000000000000000000000000000..492aed203098bb41919310368fee37df8b38cd70 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/HttpsHeadersEnableTest.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + --> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/variations.xsd"> + <testCase name="Magento\Backend\Test\TestCase\HttpsHeadersEnableTest" summary="HTTPS header options" ticketId="MAGETWO-46903"> + <variation name="EnableHttpsHeaderOptions" summary="Enable HTTPS header options" ticketId="MAGETWO-46903"> + <data name="httpsConfig/dataset" xsi:type="string">enable_https_frontend_admin</data> + <data name="hsts/dataset" xsi:type="string">enable_hsts</data> + <data name="upgradeInsecure/dataset" xsi:type="string">enable_upgrade_insecure</data> + <constraint name="Magento\Backend\Test\Constraint\AssertHttpsHeaderOptionsAvailable"/> + </variation> + </testCase> +</config> + diff --git a/lib/internal/Credis/Client.php b/lib/internal/Credis/Client.php deleted file mode 100644 index 5945709b837c8c54cf4c8116dee870f8481a0c46..0000000000000000000000000000000000000000 --- a/lib/internal/Credis/Client.php +++ /dev/null @@ -1,1113 +0,0 @@ -<?php -/** - * Credis_Client (a fork of Redisent) - * - * Most commands are compatible with phpredis library: - * - use "pipeline()" to start a pipeline of commands instead of multi(Redis::PIPELINE) - * - any arrays passed as arguments will be flattened automatically - * - setOption and getOption are not supported in standalone mode - * - order of arguments follows redis-cli instead of phpredis where they differ (lrem) - * - * - Uses phpredis library if extension is installed for better performance. - * - Establishes connection lazily. - * - Supports tcp and unix sockets. - * - Reconnects automatically unless a watch or transaction is in progress. - * - Can set automatic retry connection attempts for iffy Redis connections. - * - * @author Colin Mollenhour <colin@mollenhour.com> - * @copyright 2011 Colin Mollenhour <colin@mollenhour.com> - * @license http://www.opensource.org/licenses/mit-license.php The MIT License - * @package Credis_Client - */ - -if( ! defined('CRLF')) define('CRLF', sprintf('%s%s', chr(13), chr(10))); - -/** - * Credis-specific errors, wraps native Redis errors - */ -class CredisException extends Exception -{ - - const CODE_TIMED_OUT = 1; - const CODE_DISCONNECTED = 2; - - public function __construct($message, $code = 0, $exception = NULL) - { - if ($exception && get_class($exception) == 'RedisException' && $message == 'read error on connection') { - $code = CredisException::CODE_DISCONNECTED; - } - parent::__construct($message, $code, $exception); - } - -} - -/** - * Credis_Client, a lightweight Redis PHP standalone client and phpredis wrapper - * - * Server/Connection: - * @method Credis_Client pipeline() - * @method Credis_Client multi() - * @method array exec() - * @method string flushAll() - * @method string flushDb() - * @method array info() - * @method bool|array config(string $setGet, string $key, string $value = null) - * - * Keys: - * @method int del(string $key) - * @method int exists(string $key) - * @method int expire(string $key, int $seconds) - * @method int expireAt(string $key, int $timestamp) - * @method array keys(string $key) - * @method int persist(string $key) - * @method bool rename(string $key, string $newKey) - * @method bool renameNx(string $key, string $newKey) - * @method array sort(string $key, string $arg1, string $valueN = null) - * @method int ttl(string $key) - * @method string type(string $key) - * - * Scalars: - * @method int append(string $key, string $value) - * @method int decr(string $key) - * @method int decrBy(string $key, int $decrement) - * @method bool|string get(string $key) - * @method int getBit(string $key, int $offset) - * @method string getRange(string $key, int $start, int $end) - * @method string getSet(string $key, string $value) - * @method int incr(string $key) - * @method int incrBy(string $key, int $decrement) - * @method array mGet(array $keys) - * @method bool mSet(array $keysValues) - * @method int mSetNx(array $keysValues) - * @method bool set(string $key, string $value) - * @method int setBit(string $key, int $offset, int $value) - * @method bool setEx(string $key, int $seconds, string $value) - * @method int setNx(string $key, string $value) - * @method int setRange(string $key, int $offset, int $value) - * @method int strLen(string $key) - * - * Sets: - * @method int sAdd(string $key, mixed $value, string $valueN = null) - * @method int sRem(string $key, mixed $value, string $valueN = null) - * @method array sMembers(string $key) - * @method array sUnion(mixed $keyOrArray, string $valueN = null) - * @method array sInter(mixed $keyOrArray, string $valueN = null) - * @method array sDiff(mixed $keyOrArray, string $valueN = null) - * @method string sPop(string $key) - * @method int sCard(string $key) - * @method int sIsMember(string $key, string $member) - * @method int sMove(string $source, string $dest, string $member) - * @method string|array sRandMember(string $key, int $count = null) - * @method int sUnionStore(string $dest, string $key1, string $key2 = null) - * @method int sInterStore(string $dest, string $key1, string $key2 = null) - * @method int sDiffStore(string $dest, string $key1, string $key2 = null) - * - * Hashes: - * @method bool|int hSet(string $key, string $field, string $value) - * @method bool hSetNx(string $key, string $field, string $value) - * @method bool|string hGet(string $key, string $field) - * @method bool|int hLen(string $key) - * @method bool hDel(string $key, string $field) - * @method array hKeys(string $key, string $field) - * @method array hVals(string $key, string $field) - * @method array hGetAll(string $key) - * @method bool hExists(string $key, string $field) - * @method int hIncrBy(string $key, string $field, int $value) - * @method bool hMSet(string $key, array $keysValues) - * @method array hMGet(string $key, array $fields) - * - * Lists: - * @method array|null blPop(string $keyN, int $timeout) - * @method array|null brPop(string $keyN, int $timeout) - * @method array|null brPoplPush(string $source, string $destination, int $timeout) - * @method string|null lIndex(string $key, int $index) - * @method int lInsert(string $key, string $beforeAfter, string $pivot, string $value) - * @method int lLen(string $key) - * @method string|null lPop(string $key) - * @method int lPush(string $key, mixed $value, mixed $valueN = null) - * @method int lPushX(string $key, mixed $value) - * @method array lRange(string $key, int $start, int $stop) - * @method int lRem(string $key, int $count, mixed $value) - * @method bool lSet(string $key, int $index, mixed $value) - * @method bool lTrim(string $key, int $start, int $stop) - * @method string|null rPop(string $key) - * @method string|null rPoplPush(string $source, string $destination) - * @method int rPush(string $key, mixed $value, mixed $valueN = null) - * @method int rPushX(string $key, mixed $value) - * - * Sorted Sets: - * TODO - * - * Pub/Sub - * @method array pUnsubscribe(mixed $pattern, string $patternN = NULL)) - * @method array unsubscribe(mixed $channel, string $channelN = NULL)) - * @method int publish(string $channel, string $message) - * @method int|array pubsub(string $subCommand, $arg = NULL) - * - * Scripting: - * @method string|int script(string $command, string $arg1 = null) - * @method string|int|array|bool eval(string $script, array $keys = NULL, array $args = NULL) - * @method string|int|array|bool evalSha(string $script, array $keys = NULL, array $args = NULL) - */ -class Credis_Client { - - const TYPE_STRING = 'string'; - const TYPE_LIST = 'list'; - const TYPE_SET = 'set'; - const TYPE_ZSET = 'zset'; - const TYPE_HASH = 'hash'; - const TYPE_NONE = 'none'; - const FREAD_BLOCK_SIZE = 8192; - - /** - * Socket connection to the Redis server or Redis library instance - * @var resource|Redis - */ - protected $redis; - protected $redisMulti; - - /** - * Host of the Redis server - * @var string - */ - protected $host; - - /** - * Port on which the Redis server is running - * @var integer - */ - protected $port; - - /** - * Timeout for connecting to Redis server - * @var float - */ - protected $timeout; - - /** - * Timeout for reading response from Redis server - * @var float - */ - protected $readTimeout; - - /** - * Unique identifier for persistent connections - * @var string - */ - protected $persistent; - - /** - * @var bool - */ - protected $closeOnDestruct = TRUE; - - /** - * @var bool - */ - protected $connected = FALSE; - - /** - * @var bool - */ - protected $standalone; - - /** - * @var int - */ - protected $maxConnectRetries = 0; - - /** - * @var int - */ - protected $connectFailures = 0; - - /** - * @var bool - */ - protected $usePipeline = FALSE; - - /** - * @var array - */ - protected $commandNames; - - /** - * @var string - */ - protected $commands; - - /** - * @var bool - */ - protected $isMulti = FALSE; - - /** - * @var bool - */ - protected $isWatching = FALSE; - - /** - * @var string - */ - protected $authPassword; - - /** - * @var int - */ - protected $selectedDb = 0; - - /** - * Aliases for backwards compatibility with phpredis - * @var array - */ - protected $wrapperMethods = array('delete' => 'del', 'getkeys' => 'keys', 'sremove' => 'srem'); - - /** - * @var array - */ - protected $renamedCommands; - - /** - * @var int - */ - protected $requests = 0; - - /** - * Creates a Redisent connection to the Redis server on host {@link $host} and port {@link $port}. - * $host may also be a path to a unix socket or a string in the form of tcp://[hostname]:[port] or unix://[path] - * - * @param string $host The hostname of the Redis server - * @param integer $port The port number of the Redis server - * @param float $timeout Timeout period in seconds - * @param string $persistent Flag to establish persistent connection - * @param int $db The selected datbase of the Redis server - * @param string $password The authentication password of the Redis server - */ - public function __construct($host = '127.0.0.1', $port = 6379, $timeout = null, $persistent = '', $db = 0, $password = null) - { - $this->host = (string) $host; - $this->port = (int) $port; - $this->timeout = $timeout; - $this->persistent = (string) $persistent; - $this->standalone = ! extension_loaded('redis'); - $this->authPassword = $password; - $this->selectedDb = (int)$db; - $this->convertHost(); - } - - public function __destruct() - { - if ($this->closeOnDestruct) { - $this->close(); - } - } - /** - * Return the host of the Redis instance - * @return string - */ - public function getHost() - { - return $this->host; - } - /** - * Return the port of the Redis instance - * @return int - */ - public function getPort() - { - return $this->port; - } - - /** - * Return the selected database - * @return int - */ - public function getSelectedDb() - { - return $this->selectedDb; - } - /** - * @return string - */ - public function getPersistence() - { - return $this->persistent; - } - /** - * @throws CredisException - * @return Credis_Client - */ - public function forceStandalone() - { - if($this->connected) { - throw new CredisException('Cannot force Credis_Client to use standalone PHP driver after a connection has already been established.'); - } - $this->standalone = TRUE; - return $this; - } - - /** - * @param int $retries - * @return Credis_Client - */ - public function setMaxConnectRetries($retries) - { - $this->maxConnectRetries = $retries; - return $this; - } - - /** - * @param bool $flag - * @return Credis_Client - */ - public function setCloseOnDestruct($flag) - { - $this->closeOnDestruct = $flag; - return $this; - } - protected function convertHost() - { - if (preg_match('#^(tcp|unix)://(.*)$#', $this->host, $matches)) { - if($matches[1] == 'tcp') { - if ( ! preg_match('#^([^:]+)(:([0-9]+))?(/(.+))?$#', $matches[2], $matches)) { - throw new CredisException('Invalid host format; expected tcp://host[:port][/persistence_identifier]'); - } - $this->host = $matches[1]; - $this->port = (int) (isset($matches[3]) ? $matches[3] : 6379); - $this->persistent = isset($matches[5]) ? $matches[5] : ''; - } else { - $this->host = $matches[2]; - $this->port = NULL; - if (substr($this->host,0,1) != '/') { - throw new CredisException('Invalid unix socket format; expected unix:///path/to/redis.sock'); - } - } - } - if ($this->port !== NULL && substr($this->host,0,1) == '/') { - $this->port = NULL; - } - } - /** - * @throws CredisException - * @return Credis_Client - */ - public function connect() - { - if ($this->connected) { - return $this; - } - if ($this->standalone) { - $flags = STREAM_CLIENT_CONNECT; - $remote_socket = $this->port === NULL - ? 'unix://'.$this->host - : 'tcp://'.$this->host.':'.$this->port; - if ($this->persistent) { - if ($this->port === NULL) { // Unix socket - throw new CredisException('Persistent connections to UNIX sockets are not supported in standalone mode.'); - } - $remote_socket .= '/'.$this->persistent; - $flags = $flags | STREAM_CLIENT_PERSISTENT; - } - $result = $this->redis = @stream_socket_client($remote_socket, $errno, $errstr, $this->timeout !== null ? $this->timeout : 2.5, $flags); - } - else { - if ( ! $this->redis) { - $this->redis = new Redis; - } - $result = $this->persistent - ? $this->redis->pconnect($this->host, $this->port, $this->timeout, $this->persistent) - : $this->redis->connect($this->host, $this->port, $this->timeout); - } - - // Use recursion for connection retries - if ( ! $result) { - $this->connectFailures++; - if ($this->connectFailures <= $this->maxConnectRetries) { - return $this->connect(); - } - $failures = $this->connectFailures; - $this->connectFailures = 0; - throw new CredisException("Connection to Redis failed after $failures failures." . (isset($errno) && isset($errstr) ? "Last Error : ({$errno}) {$errstr}" : "")); - } - - $this->connectFailures = 0; - $this->connected = TRUE; - - // Set read timeout - if ($this->readTimeout) { - $this->setReadTimeout($this->readTimeout); - } - - if($this->authPassword !== null) { - $this->auth($this->authPassword); - } - if($this->selectedDb !== 0) { - $this->select($this->selectedDb); - } - return $this; - } - /** - * @return bool - */ - public function isConnected() - { - return $this->connected; - } - /** - * Set the read timeout for the connection. Use 0 to disable timeouts entirely (or use a very long timeout - * if not supported). - * - * @param int $timeout 0 (or -1) for no timeout, otherwise number of seconds - * @throws CredisException - * @return Credis_Client - */ - public function setReadTimeout($timeout) - { - if ($timeout < -1) { - throw new CredisException('Timeout values less than -1 are not accepted.'); - } - $this->readTimeout = $timeout; - if ($this->connected) { - if ($this->standalone) { - $timeout = $timeout <= 0 ? 315360000 : $timeout; // Ten-year timeout - stream_set_blocking($this->redis, TRUE); - stream_set_timeout($this->redis, (int) floor($timeout), ($timeout - floor($timeout)) * 1000000); - } else if (defined('Redis::OPT_READ_TIMEOUT')) { - // supported in phpredis 2.2.3 - // a timeout value of -1 means reads will not timeout - $timeout = $timeout == 0 ? -1 : $timeout; - $this->redis->setOption(Redis::OPT_READ_TIMEOUT, $timeout); - } - } - return $this; - } - - /** - * @return bool - */ - public function close() - { - $result = TRUE; - if ($this->connected && ! $this->persistent) { - try { - $result = $this->standalone ? fclose($this->redis) : $this->redis->close(); - $this->connected = FALSE; - } catch (Exception $e) { - ; // Ignore exceptions on close - } - } - return $result; - } - - /** - * Enabled command renaming and provide mapping method. Supported methods are: - * - * 1. renameCommand('foo') // Salted md5 hash for all commands -> md5('foo'.$command) - * 2. renameCommand(function($command){ return 'my'.$command; }); // Callable - * 3. renameCommand('get', 'foo') // Single command -> alias - * 4. renameCommand(['get' => 'foo', 'set' => 'bar']) // Full map of [command -> alias] - * - * @param string|callable|array $command - * @param string|null $alias - * @return $this - */ - public function renameCommand($command, $alias = NULL) - { - if ( ! $this->standalone) { - $this->forceStandalone(); - } - if ($alias === NULL) { - $this->renamedCommands = $command; - } else { - if ( ! $this->renamedCommands) { - $this->renamedCommands = array(); - } - $this->renamedCommands[$command] = $alias; - } - return $this; - } - - /** - * @param $command - */ - public function getRenamedCommand($command) - { - static $map; - - // Command renaming not enabled - if ($this->renamedCommands === NULL) { - return $command; - } - - // Initialize command map - if ($map === NULL) { - if (is_array($this->renamedCommands)) { - $map = $this->renamedCommands; - } else { - $map = array(); - } - } - - // Generate and return cached result - if ( ! isset($map[$command])) { - // String means all commands are hashed with salted md5 - if (is_string($this->renamedCommands)) { - $map[$command] = md5($this->renamedCommands.$command); - } - // Would already be set in $map if it was intended to be renamed - else if (is_array($this->renamedCommands)) { - return $command; - } - // User-supplied function - else if (is_callable($this->renamedCommands)) { - $map[$command] = call_user_func($this->renamedCommands, $command); - } - } - return $map[$command]; - } - - /** - * @param string $password - * @return bool - */ - public function auth($password) - { - $response = $this->__call('auth', array($password)); - $this->authPassword = $password; - return $response; - } - - /** - * @param int $index - * @return bool - */ - public function select($index) - { - $response = $this->__call('select', array($index)); - $this->selectedDb = (int) $index; - return $response; - } - - /** - * @param string|array $patterns - * @param $callback - * @return $this|array|bool|Credis_Client|mixed|null|string - * @throws CredisException - */ - public function pSubscribe($patterns, $callback) - { - if ( ! $this->standalone) { - return $this->__call('pSubscribe', array((array)$patterns, $callback)); - } - - // Standalone mode: use infinite loop to subscribe until timeout - $patternCount = is_array($patterns) ? count($patterns) : 1; - while ($patternCount--) { - if (isset($status)) { - list($command, $pattern, $status) = $this->read_reply(); - } else { - list($command, $pattern, $status) = $this->__call('psubscribe', array($patterns)); - } - if ( ! $status) { - throw new CredisException('Invalid pSubscribe response.'); - } - } - try { - while (1) { - list($type, $pattern, $channel, $message) = $this->read_reply(); - if ($type != 'pmessage') { - throw new CredisException('Received non-pmessage reply.'); - } - $callback($this, $pattern, $channel, $message); - } - } catch (CredisException $e) { - if ($e->getCode() == CredisException::CODE_TIMED_OUT) { - try { - list($command, $pattern, $status) = $this->pUnsubscribe($patterns); - while ($status !== 0) { - list($command, $pattern, $status) = $this->read_reply(); - } - } catch (CredisException $e2) { - throw $e2; - } - } - throw $e; - } - } - - /** - * @param string|array $channels - * @param $callback - * @throws CredisException - * @return $this|array|bool|Credis_Client|mixed|null|string - */ - public function subscribe($channels, $callback) - { - if ( ! $this->standalone) { - return $this->__call('subscribe', array((array)$channels, $callback)); - } - - // Standalone mode: use infinite loop to subscribe until timeout - $channelCount = is_array($channels) ? count($channels) : 1; - while ($channelCount--) { - if (isset($status)) { - list($command, $channel, $status) = $this->read_reply(); - } else { - list($command, $channel, $status) = $this->__call('subscribe', array($channels)); - } - if ( ! $status) { - throw new CredisException('Invalid subscribe response.'); - } - } - try { - while (1) { - list($type, $channel, $message) = $this->read_reply(); - if ($type != 'message') { - throw new CredisException('Received non-message reply.'); - } - $callback($this, $channel, $message); - } - } catch (CredisException $e) { - if ($e->getCode() == CredisException::CODE_TIMED_OUT) { - try { - list($command, $channel, $status) = $this->unsubscribe($channels); - while ($status !== 0) { - list($command, $channel, $status) = $this->read_reply(); - } - } catch (CredisException $e2) { - throw $e2; - } - } - throw $e; - } - } - - public function __call($name, $args) - { - // Lazy connection - $this->connect(); - - $name = strtolower($name); - - // Send request via native PHP - if($this->standalone) - { - switch ($name) { - case 'eval': - case 'evalsha': - $script = array_shift($args); - $keys = (array) array_shift($args); - $eArgs = (array) array_shift($args); - $args = array($script, count($keys), $keys, $eArgs); - break; - } - // Flatten arguments - $argsFlat = NULL; - foreach($args as $index => $arg) { - if(is_array($arg)) { - if($argsFlat === NULL) { - $argsFlat = array_slice($args, 0, $index); - } - if($name == 'mset' || $name == 'msetnx' || $name == 'hmset') { - foreach($arg as $key => $value) { - $argsFlat[] = $key; - $argsFlat[] = $value; - } - } else { - $argsFlat = array_merge($argsFlat, $arg); - } - } else if($argsFlat !== NULL) { - $argsFlat[] = $arg; - } - } - if($argsFlat !== NULL) { - $args = $argsFlat; - $argsFlat = NULL; - } - - // In pipeline mode - if($this->usePipeline) - { - if($name == 'pipeline') { - throw new CredisException('A pipeline is already in use and only one pipeline is supported.'); - } - else if($name == 'exec') { - if($this->isMulti) { - $this->commandNames[] = $name; - $this->commands .= self::_prepare_command(array($this->getRenamedCommand($name))); - } - - // Write request - if($this->commands) { - $this->write_command($this->commands); - } - $this->commands = NULL; - - // Read response - $response = array(); - foreach($this->commandNames as $command) { - $response[] = $this->read_reply($command); - } - $this->commandNames = NULL; - - if($this->isMulti) { - $response = array_pop($response); - } - $this->usePipeline = $this->isMulti = FALSE; - return $response; - } - else { - if($name == 'multi') { - $this->isMulti = TRUE; - } - array_unshift($args, $this->getRenamedCommand($name)); - $this->commandNames[] = $name; - $this->commands .= self::_prepare_command($args); - return $this; - } - } - - // Start pipeline mode - if($name == 'pipeline') - { - $this->usePipeline = TRUE; - $this->commandNames = array(); - $this->commands = ''; - return $this; - } - - // If unwatching, allow reconnect with no error thrown - if($name == 'unwatch') { - $this->isWatching = FALSE; - } - - // Non-pipeline mode - array_unshift($args, $this->getRenamedCommand($name)); - $command = self::_prepare_command($args); - $this->write_command($command); - $response = $this->read_reply($name); - - // Watch mode disables reconnect so error is thrown - if($name == 'watch') { - $this->isWatching = TRUE; - } - // Transaction mode - else if($this->isMulti && ($name == 'exec' || $name == 'discard')) { - $this->isMulti = FALSE; - } - // Started transaction - else if($this->isMulti || $name == 'multi') { - $this->isMulti = TRUE; - $response = $this; - } - } - - // Send request via phpredis client - else - { - // Tweak arguments - switch($name) { - case 'get': // optimize common cases - case 'set': - case 'hget': - case 'hset': - case 'setex': - case 'mset': - case 'msetnx': - case 'hmset': - case 'hmget': - case 'del': - break; - case 'mget': - if(isset($args[0]) && ! is_array($args[0])) { - $args = array($args); - } - break; - case 'lrem': - $args = array($args[0], $args[2], $args[1]); - break; - case 'eval': - case 'evalsha': - if (isset($args[1]) && is_array($args[1])) { - $cKeys = $args[1]; - } elseif (isset($args[1]) && is_string($args[1])) { - $cKeys = array($args[1]); - } else { - $cKeys = array(); - } - if (isset($args[2]) && is_array($args[2])) { - $cArgs = $args[2]; - } elseif (isset($args[2]) && is_string($args[2])) { - $cArgs = array($args[2]); - } else { - $cArgs = array(); - } - $args = array($args[0], array_merge($cKeys, $cArgs), count($cKeys)); - break; - case 'subscribe': - case 'psubscribe': - break; - default: - // Flatten arguments - $argsFlat = NULL; - foreach($args as $index => $arg) { - if(is_array($arg)) { - if($argsFlat === NULL) { - $argsFlat = array_slice($args, 0, $index); - } - $argsFlat = array_merge($argsFlat, $arg); - } else if($argsFlat !== NULL) { - $argsFlat[] = $arg; - } - } - if($argsFlat !== NULL) { - $args = $argsFlat; - $argsFlat = NULL; - } - } - - try { - // Proxy pipeline mode to the phpredis library - if($name == 'pipeline' || $name == 'multi') { - if($this->isMulti) { - return $this; - } else { - $this->isMulti = TRUE; - $this->redisMulti = call_user_func_array(array($this->redis, $name), $args); - } - } - else if($name == 'exec' || $name == 'discard') { - $this->isMulti = FALSE; - $response = $this->redisMulti->$name(); - $this->redisMulti = NULL; - #echo "> $name : ".substr(print_r($response, TRUE),0,100)."\n"; - return $response; - } - - // Use aliases to be compatible with phpredis wrapper - if(isset($this->wrapperMethods[$name])) { - $name = $this->wrapperMethods[$name]; - } - - // Multi and pipeline return self for chaining - if($this->isMulti) { - call_user_func_array(array($this->redisMulti, $name), $args); - return $this; - } - - // Send request, retry one time when using persistent connections on the first request only - $this->requests++; - try { - $response = call_user_func_array(array($this->redis, $name), $args); - } catch (RedisException $e) { - if ($this->persistent && $this->requests == 1 && $e->getMessage() == 'read error on connection') { - $this->connected = FALSE; - $this->connect(); - $response = call_user_func_array(array($this->redis, $name), $args); - } else { - throw $e; - } - } - } - // Wrap exceptions - catch(RedisException $e) { - $code = 0; - if ( ! ($result = $this->redis->IsConnected())) { - $this->connected = FALSE; - $code = CredisException::CODE_DISCONNECTED; - } - throw new CredisException($e->getMessage(), $code, $e); - } - - #echo "> $name : ".substr(print_r($response, TRUE),0,100)."\n"; - - // change return values where it is too difficult to minim in standalone mode - switch($name) - { - case 'hmget': - $response = array_values($response); - break; - - case 'type': - $typeMap = array( - self::TYPE_NONE, - self::TYPE_STRING, - self::TYPE_SET, - self::TYPE_LIST, - self::TYPE_ZSET, - self::TYPE_HASH, - ); - $response = $typeMap[$response]; - break; - - // Handle scripting errors - case 'eval': - case 'evalsha': - case 'script': - $error = $this->redis->getLastError(); - $this->redis->clearLastError(); - if ($error && substr($error,0,8) == 'NOSCRIPT') { - $response = NULL; - } else if ($error) { - throw new CredisException($error); - } - break; - default: - $error = $this->redis->getLastError(); - $this->redis->clearLastError(); - if ($error) { - throw new CredisException($error); - } - break; - } - } - - return $response; - } - - protected function write_command($command) - { - // Reconnect on lost connection (Redis server "timeout" exceeded since last command) - if(feof($this->redis)) { - $this->close(); - // If a watch or transaction was in progress and connection was lost, throw error rather than reconnect - // since transaction/watch state will be lost. - if(($this->isMulti && ! $this->usePipeline) || $this->isWatching) { - $this->isMulti = $this->isWatching = FALSE; - throw new CredisException('Lost connection to Redis server during watch or transaction.'); - } - $this->connected = FALSE; - $this->connect(); - if($this->authPassword) { - $this->auth($this->authPassword); - } - if($this->selectedDb != 0) { - $this->select($this->selectedDb); - } - } - - $commandLen = strlen($command); - for ($written = 0; $written < $commandLen; $written += $fwrite) { - $fwrite = fwrite($this->redis, substr($command, $written)); - if ($fwrite === FALSE || $fwrite == 0 ) { - $this->connected = FALSE; - throw new CredisException('Failed to write entire command to stream'); - } - } - } - - protected function read_reply($name = '') - { - $reply = fgets($this->redis); - if($reply === FALSE) { - $info = stream_get_meta_data($this->redis); - if ($info['timed_out']) { - throw new CredisException('Read operation timed out.', CredisException::CODE_TIMED_OUT); - } else { - $this->connected = FALSE; - throw new CredisException('Lost connection to Redis server.', CredisException::CODE_DISCONNECTED); - } - } - $reply = rtrim($reply, CRLF); - #echo "> $name: $reply\n"; - $replyType = substr($reply, 0, 1); - switch ($replyType) { - /* Error reply */ - case '-': - if($this->isMulti || $this->usePipeline) { - $response = FALSE; - } else if ($name == 'evalsha' && substr($reply,0,9) == '-NOSCRIPT') { - $response = NULL; - } else { - throw new CredisException(substr($reply,0,4) == '-ERR' ? substr($reply, 5) : substr($reply,1)); - } - break; - /* Inline reply */ - case '+': - $response = substr($reply, 1); - if($response == 'OK' || $response == 'QUEUED') { - return TRUE; - } - break; - /* Bulk reply */ - case '$': - if ($reply == '$-1') return FALSE; - $size = (int) substr($reply, 1); - $response = stream_get_contents($this->redis, $size + 2); - if( ! $response) { - $this->connected = FALSE; - throw new CredisException('Error reading reply.'); - } - $response = substr($response, 0, $size); - break; - /* Multi-bulk reply */ - case '*': - $count = substr($reply, 1); - if ($count == '-1') return FALSE; - - $response = array(); - for ($i = 0; $i < $count; $i++) { - $response[] = $this->read_reply(); - } - break; - /* Integer reply */ - case ':': - $response = intval(substr($reply, 1)); - break; - default: - throw new CredisException('Invalid response: '.print_r($reply, TRUE)); - break; - } - - // Smooth over differences between phpredis and standalone response - switch($name) - { - case '': // Minor optimization for multi-bulk replies - break; - case 'config': - case 'hgetall': - $keys = $values = array(); - while($response) { - $keys[] = array_shift($response); - $values[] = array_shift($response); - } - $response = count($keys) ? array_combine($keys, $values) : array(); - break; - case 'info': - $lines = explode(CRLF, trim($response,CRLF)); - $response = array(); - foreach($lines as $line) { - if ( ! $line || substr($line, 0, 1) == '#') { - continue; - } - list($key, $value) = explode(':', $line, 2); - $response[$key] = $value; - } - break; - case 'ttl': - if($response === -1) { - $response = FALSE; - } - break; - } - - return $response; - } - - /** - * Build the Redis unified protocol command - * - * @param array $args - * @return string - */ - private static function _prepare_command($args) - { - return sprintf('*%d%s%s%s', count($args), CRLF, implode(array_map(array('self', '_map'), $args), CRLF), CRLF); - } - - private static function _map($arg) - { - return sprintf('$%d%s%s', strlen($arg), CRLF, $arg); - } - -} diff --git a/lib/internal/Magento/Framework/Config/ConfigOptionsListConstants.php b/lib/internal/Magento/Framework/Config/ConfigOptionsListConstants.php index c49d92ee281ce439e2cd948ed3df606624f9a525..4fbeaecc85d18ad7c22f386ecfd00d838d5b904d 100644 --- a/lib/internal/Magento/Framework/Config/ConfigOptionsListConstants.php +++ b/lib/internal/Magento/Framework/Config/ConfigOptionsListConstants.php @@ -56,6 +56,7 @@ class ConfigOptionsListConstants */ const SESSION_SAVE_FILES = 'files'; const SESSION_SAVE_DB = 'db'; + const SESSION_SAVE_REDIS = 'redis'; /**#@-*/ /** diff --git a/lib/internal/Magento/Framework/DB/Select/SelectRenderer.php b/lib/internal/Magento/Framework/DB/Select/SelectRenderer.php index 9866775d1fecdd1d381a3058483cba1d828342dd..10b388638222c15e760a14a9b56722da1cf378ce 100644 --- a/lib/internal/Magento/Framework/DB/Select/SelectRenderer.php +++ b/lib/internal/Magento/Framework/DB/Select/SelectRenderer.php @@ -65,7 +65,7 @@ class SelectRenderer implements RendererInterface */ public function render(Select $select, $sql = '') { - $sql = Select::SQL_SELECT . ' '; + $sql = Select::SQL_SELECT; foreach ($this->renderers as $renderer) { if (in_array($renderer['part'], [Select::COLUMNS, Select::FROM]) || $select->getPart($renderer['part'])) { $sql = $renderer['renderer']->render($select, $sql); diff --git a/lib/internal/Magento/Framework/Session/Config.php b/lib/internal/Magento/Framework/Session/Config.php index f006da9dcf7b376505f64d7c8485997fe925ba1e..793794b61826e09f088fef985593e40aae9aada5 100644 --- a/lib/internal/Magento/Framework/Session/Config.php +++ b/lib/internal/Magento/Framework/Session/Config.php @@ -15,8 +15,6 @@ use Magento\Framework\Session\SaveHandlerInterface; /** * Magento session configuration - * - * @method Config setSaveHandler() */ class Config implements ConfigInterface { @@ -99,6 +97,11 @@ class Config implements ConfigInterface */ protected $_scopeType; + /** + * @var string + */ + private $saveHandlerName; + /** @var \Magento\Framework\ValidatorFactory */ protected $_validatorFactory; @@ -141,7 +144,6 @@ class Config implements ConfigInterface self::PARAM_SESSION_SAVE_METHOD, $defaultSaveHandler ); - $saveMethod = $saveMethod === 'db' ? 'user' : $saveMethod; $this->setSaveHandler($saveMethod); /** @@ -292,6 +294,38 @@ class Config implements ConfigInterface return (string)$this->getOption('session.name'); } + /** + * {@inheritdoc} + */ + public function setSaveHandler($saveHandler) + { + $this->setSaveHandlerName($saveHandler); + if ($saveHandler === 'db' || $saveHandler === 'redis') { + $saveHandler = 'user'; + } + $this->setOption('session.save_handler', $saveHandler); + return $this; + } + + /** + * Set save handler name + * + * @param string $saveHandlerName + * @return void + */ + private function setSaveHandlerName($saveHandlerName) + { + $this->saveHandlerName = $saveHandlerName; + } + + /** + * {@inheritdoc} + */ + public function getSaveHandlerName() + { + return $this->saveHandlerName; + } + /** * Set session.save_path * diff --git a/lib/internal/Magento/Framework/Session/Config/ConfigInterface.php b/lib/internal/Magento/Framework/Session/Config/ConfigInterface.php index 6c2372d20be4fc7c759618cdda8a93dfad19fc21..8182a7638efd358333bc6ee23b0a95e58b32b605 100644 --- a/lib/internal/Magento/Framework/Session/Config/ConfigInterface.php +++ b/lib/internal/Magento/Framework/Session/Config/ConfigInterface.php @@ -170,4 +170,19 @@ interface ConfigInterface * @SuppressWarnings(PHPMD.BooleanGetMethodName) */ public function getUseCookies(); + + /** + * Get save handler name + * + * @return string + */ + public function getSaveHandlerName(); + + /** + * Set session.save_handler + * + * @param string $saveHandler + * @return $this + */ + public function setSaveHandler($saveHandler); } diff --git a/lib/internal/Magento/Framework/Session/SaveHandler.php b/lib/internal/Magento/Framework/Session/SaveHandler.php index 3e7b593dfcf5e73b149898968c7a1281dea08cb1..e4ec505a2cea873f6364e4ecc5472e523127309e 100644 --- a/lib/internal/Magento/Framework/Session/SaveHandler.php +++ b/lib/internal/Magento/Framework/Session/SaveHandler.php @@ -5,8 +5,8 @@ */ namespace Magento\Framework\Session; -use Magento\Framework\App\DeploymentConfig; use Magento\Framework\Exception\SessionException; +use Magento\Framework\Session\Config\ConfigInterface; /** * Magento session save handler @@ -24,19 +24,20 @@ class SaveHandler implements SaveHandlerInterface * Constructor * * @param SaveHandlerFactory $saveHandlerFactory - * @param DeploymentConfig $deploymentConfig + * @param ConfigInterface $config * @param string $default */ public function __construct( SaveHandlerFactory $saveHandlerFactory, - DeploymentConfig $deploymentConfig, + ConfigInterface $config, $default = self::DEFAULT_HANDLER ) { - $saveMethod = $deploymentConfig->get(\Magento\Framework\Session\Config::PARAM_SESSION_SAVE_METHOD); + $saveMethod = $config->getSaveHandlerName(); try { $connection = $saveHandlerFactory->create($saveMethod); } catch (SessionException $e) { $connection = $saveHandlerFactory->create($default); + $config->setSaveHandler($default); } $this->saveHandlerAdapter = $connection; } diff --git a/lib/internal/Magento/Framework/Session/SaveHandler/Redis.php b/lib/internal/Magento/Framework/Session/SaveHandler/Redis.php new file mode 100644 index 0000000000000000000000000000000000000000..56ce5cc075d7f296303768479b2059308b567f6d --- /dev/null +++ b/lib/internal/Magento/Framework/Session/SaveHandler/Redis.php @@ -0,0 +1,51 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Session\SaveHandler; + +use Cm\RedisSession\Handler\ConfigInterface; +use Cm\RedisSession\Handler\LoggerInterface; +use Cm\RedisSession\ConnectionFailedException; +use Cm\RedisSession\ConcurrentConnectionsExceededException; +use Magento\Framework\Exception\SessionException; +use Magento\Framework\Phrase; +use Magento\Framework\Filesystem; +use Magento\Framework\App\Filesystem\DirectoryList; + +class Redis extends \Cm\RedisSession\Handler +{ + /** + * @var Filesystem + */ + private $filesystem; + + /** + * @param ConfigInterface $config + * @param LoggerInterface $logger + * @param Filesystem $filesystem + * @throws SessionException + */ + public function __construct(ConfigInterface $config, LoggerInterface $logger, Filesystem $filesystem) + { + $this->filesystem = $filesystem; + try { + parent::__construct($config, $logger); + } catch (ConnectionFailedException $e) { + throw new SessionException(new Phrase($e->getMessage())); + } + } + + /** + * {@inheritdoc} + */ + public function read($sessionId) + { + try { + return parent::read($sessionId); + } catch (ConcurrentConnectionsExceededException $e) { + require $this->filesystem->getDirectoryRead(DirectoryList::PUB)->getAbsolutePath('errors/503.php'); + } + } +} diff --git a/lib/internal/Magento/Framework/Session/SaveHandler/Redis/Config.php b/lib/internal/Magento/Framework/Session/SaveHandler/Redis/Config.php new file mode 100644 index 0000000000000000000000000000000000000000..a20878c4026016db3c31f9dc780a980e0b1590ca --- /dev/null +++ b/lib/internal/Magento/Framework/Session/SaveHandler/Redis/Config.php @@ -0,0 +1,250 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Session\SaveHandler\Redis; + +use Magento\Framework\App\DeploymentConfig; +use Magento\Framework\App\State; + +class Config implements \Cm\RedisSession\Handler\ConfigInterface +{ + /** + * Configuration path for log level + */ + const PARAM_LOG_LEVEL = 'session/redis/log_level'; + + /** + * Configuration path for host + */ + const PARAM_HOST = 'session/redis/host'; + + /** + * Configuration path for port + */ + const PARAM_PORT = 'session/redis/port'; + + /** + * Configuration path for database + */ + const PARAM_DATABASE = 'session/redis/database'; + + /** + * Configuration path for password + */ + const PARAM_PASSWORD = 'session/redis/password'; + + /** + * Configuration path for connection timeout + */ + const PARAM_TIMEOUT = 'session/redis/timeout'; + + /** + * Configuration path for persistent identifier + */ + const PARAM_PERSISTENT_IDENTIFIER = 'session/redis/param_persistent_identifier'; + + /** + * Configuration path for compression threshold + */ + const PARAM_COMPRESSION_THRESHOLD = 'session/redis/param_compression_threshold'; + + /** + * Configuration path for compression library + */ + const PARAM_COMPRESSION_LIBRARY = 'session/redis/compression_library'; + + /** + * Configuration path for maximum number of processes that can wait for a lock on one session + */ + const PARAM_MAX_CONCURRENCY = 'session/redis/max_concurrency'; + + /** + * Configuration path for minimum session lifetime + */ + const PARAM_MAX_LIFETIME = 'session/redis/max_lifetime'; + + /** + * Configuration path for min + */ + const PARAM_MIN_LIFETIME = 'session/redis/min_lifetime'; + + /** + * Configuration path for disabling session locking entirely flag + */ + const PARAM_DISABLE_LOCKING = 'session/redis/disable_locking'; + + /** + * Configuration path for lifetime of session for bots on subsequent writes + */ + const PARAM_BOT_LIFETIME = 'session/redis/bot_lifetime'; + + /** + * Configuration path for lifetime of session for bots on the first write + */ + const PARAM_BOT_FIRST_LIFETIME = 'session/redis/bot_first_lifetime'; + + /** + * Configuration path for lifetime of session for non-bots on the first write + */ + const PARAM_FIRST_LIFETIME = 'session/redis/first_lifetime'; + + /** + * Configuration path for number of seconds to wait before trying to break the lock + */ + const PARAM_BREAK_AFTER = 'session/redis/break_after'; + + /** + * Deployment config + * + * @var DeploymentConfig $deploymentConfig + */ + private $deploymentConfig; + + /** + * @param DeploymentConfig $deploymentConfig + * @param State $appState + */ + public function __construct(DeploymentConfig $deploymentConfig, State $appState) + { + $this->deploymentConfig = $deploymentConfig; + $this->appState = $appState; + } + + /** + * {@inheritdoc} + */ + public function getLogLevel() + { + return $this->deploymentConfig->get(self::PARAM_LOG_LEVEL); + } + + /** + * {@inheritdoc} + */ + public function getHost() + { + return $this->deploymentConfig->get(self::PARAM_HOST); + } + + /** + * {@inheritdoc} + */ + public function getPort() + { + return $this->deploymentConfig->get(self::PARAM_PORT); + } + + /** + * {@inheritdoc} + */ + public function getDatabase() + { + return $this->deploymentConfig->get(self::PARAM_DATABASE); + } + + /** + * {@inheritdoc} + */ + public function getPassword() + { + return $this->deploymentConfig->get(self::PARAM_PASSWORD); + } + + /** + * {@inheritdoc} + */ + public function getTimeout() + { + return $this->deploymentConfig->get(self::PARAM_TIMEOUT); + } + + /** + * {@inheritdoc} + */ + public function getPersistentIdentifier() + { + return $this->deploymentConfig->get(self::PARAM_PERSISTENT_IDENTIFIER); + } + + /** + * {@inheritdoc} + */ + public function getCompressionThreshold() + { + return $this->deploymentConfig->get(self::PARAM_COMPRESSION_THRESHOLD); + } + + /** + * {@inheritdoc} + */ + public function getCompressionLibrary() + { + return $this->deploymentConfig->get(self::PARAM_COMPRESSION_LIBRARY); + } + + /** + * {@inheritdoc} + */ + public function getMaxConcurrency() + { + return $this->deploymentConfig->get(self::PARAM_MAX_CONCURRENCY); + } + + /** + * {@inheritdoc} + */ + public function getMaxLifetime() + { + return $this->deploymentConfig->get(self::PARAM_MAX_LIFETIME); + } + + /** + * {@inheritdoc} + */ + public function getMinLifetime() + { + return $this->deploymentConfig->get(self::PARAM_MIN_LIFETIME); + } + + /** + * {@inheritdoc} + */ + public function getDisableLocking() + { + return $this->deploymentConfig->get(self::PARAM_DISABLE_LOCKING); + } + + /** + * {@inheritdoc} + */ + public function getBotLifetime() + { + return $this->deploymentConfig->get(self::PARAM_BOT_LIFETIME); + } + + /** + * {@inheritdoc} + */ + public function getBotFirstLifetime() + { + return $this->deploymentConfig->get(self::PARAM_BOT_FIRST_LIFETIME); + } + + /** + * {@inheritdoc} + */ + public function getFirstLifetime() + { + return $this->deploymentConfig->get(self::PARAM_FIRST_LIFETIME); + } + + /** + * {@inheritdoc} + */ + public function getBreakAfter() + { + return $this->deploymentConfig->get(self::PARAM_BREAK_AFTER . '_' . $this->appState->getAreaCode()); + } +} diff --git a/lib/internal/Magento/Framework/Session/SaveHandler/Redis/Logger.php b/lib/internal/Magento/Framework/Session/SaveHandler/Redis/Logger.php new file mode 100644 index 0000000000000000000000000000000000000000..8684f475de5f648d3b912d41fe47a3a886456c2f --- /dev/null +++ b/lib/internal/Magento/Framework/Session/SaveHandler/Redis/Logger.php @@ -0,0 +1,93 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Session\SaveHandler\Redis; + +use Cm\RedisSession\Handler\ConfigInterface; +use Psr\Log\LoggerInterface; +use Magento\Framework\App\Request\Http as Request; + +class Logger implements \Cm\RedisSession\Handler\LoggerInterface +{ + /** + * @var LoggerInterface + */ + private $logger; + + /** + * @var int + */ + private $logLevel; + + /** + * @var Request + */ + private $request; + + /** + * Logger constructor + * + * @param ConfigInterface $config + * @param LoggerInterface $logger + * @param Request $request + */ + public function __construct(ConfigInterface $config, LoggerInterface $logger, Request $request) + { + $this->logger = $logger; + $this->request = $request; + $this->logLevel = $config->getLogLevel() ?: self::ALERT; + } + + /** + * {@inheritdoc} + */ + public function setLogLevel($level) + { + $this->logLevel = $level; + } + + /** + * {@inheritdoc} + */ + public function log($message, $level) + { + $message .= ' ' . $this->request->getRequestUri(); + if ($this->logLevel >= $level) { + switch ($level) { + case self::EMERGENCY: + $this->logger->emergency($message); + break; + case self::ALERT: + $this->logger->alert($message); + break; + case self::CRITICAL: + $this->logger->critical($message); + break; + case self::ERROR: + $this->logger->error($message); + break; + case self::WARNING: + $this->logger->warning($message); + break; + case self::NOTICE: + $this->logger->notice($message); + break; + case self::INFO: + $this->logger->info($message); + break; + default: + $this->logger->debug($message); + } + } + } + + /** + * {@inheritdoc} + */ + public function logException(\Exception $e) + { + $this->logger->critical($e->getMessage()); + } +} diff --git a/lib/internal/Magento/Framework/Session/Test/Unit/ConfigTest.php b/lib/internal/Magento/Framework/Session/Test/Unit/ConfigTest.php index 6c43bf72c0d010fe2eee5d71622e33ee1044b6d6..3c50426ce22347baf077bcf3f50739b5fa73bb6d 100644 --- a/lib/internal/Magento/Framework/Session/Test/Unit/ConfigTest.php +++ b/lib/internal/Magento/Framework/Session/Test/Unit/ConfigTest.php @@ -148,8 +148,12 @@ class ConfigTest extends \PHPUnit_Framework_TestCase public function testSaveHandlerIsMutable() { $this->getModel($this->validatorMock); - $this->config->setSaveHandler('user'); + $this->config->setSaveHandler('redis'); $this->assertEquals('user', $this->config->getSaveHandler()); + $this->assertEquals('redis', $this->config->getSaveHandlerName()); + $this->config->setSaveHandler('files'); + $this->assertEquals('files', $this->config->getSaveHandler()); + $this->assertEquals('files', $this->config->getSaveHandlerName()); } public function testCookieLifetimeIsMutable() diff --git a/lib/internal/Magento/Framework/Session/Test/Unit/SaveHandler/Redis/ConfigTest.php b/lib/internal/Magento/Framework/Session/Test/Unit/SaveHandler/Redis/ConfigTest.php new file mode 100644 index 0000000000000000000000000000000000000000..30b8787753c0e2bca4397d1dd4170e62a0692b75 --- /dev/null +++ b/lib/internal/Magento/Framework/Session/Test/Unit/SaveHandler/Redis/ConfigTest.php @@ -0,0 +1,214 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Session\Test\Unit\SaveHandler\Redis; + +use Magento\Framework\Session\SaveHandler\Redis\Config; + +class ConfigTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var \Magento\Framework\App\DeploymentConfig + */ + protected $deploymentConfig; + + /** + * @var \Magento\Framework\App\State + */ + protected $appState; + + /** + * @var \Magento\Framework\Session\SaveHandler\Redis\Config + */ + protected $config; + + public function setUp() + { + $this->deploymentConfig = $this->getMock('Magento\Framework\App\DeploymentConfig', [], [], '', false); + $this->appState = $this->getMock('Magento\Framework\App\State', [], [], '', false); + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->config = $objectManager->getObject( + 'Magento\Framework\Session\SaveHandler\Redis\Config', + [ + 'deploymentConfig' => $this->deploymentConfig, + 'appState' => $this->appState + ] + ); + } + + public function testGetLogLevel() + { + $expected = 2; + $this->deploymentConfig->expects($this->once()) + ->method('get') + ->with(Config::PARAM_LOG_LEVEL) + ->willReturn($expected); + $this->assertEquals($this->config->getLogLevel(), $expected); + } + + public function testGetHost() + { + $expected = '127.0.0.1'; + $this->deploymentConfig->expects($this->once()) + ->method('get') + ->with(Config::PARAM_HOST) + ->willReturn($expected); + $this->assertEquals($this->config->getHost(), $expected); + } + + public function testGetPort() + { + $expected = 1234; + $this->deploymentConfig->expects($this->once()) + ->method('get') + ->with(Config::PARAM_PORT) + ->willReturn($expected); + $this->assertEquals($this->config->getPort(), $expected); + } + + public function testGetDatabase() + { + $expected = 2; + $this->deploymentConfig->expects($this->once()) + ->method('get') + ->with(Config::PARAM_DATABASE) + ->willReturn($expected); + $this->assertEquals($this->config->getDatabase(), $expected); + } + + public function testGetPassword() + { + $expected = 'password'; + $this->deploymentConfig->expects($this->once()) + ->method('get') + ->with(Config::PARAM_PASSWORD) + ->willReturn($expected); + $this->assertEquals($this->config->getPassword(), $expected); + } + + public function testGetTimeout() + { + $expected = 10; + $this->deploymentConfig->expects($this->once()) + ->method('get') + ->with(Config::PARAM_TIMEOUT) + ->willReturn($expected); + $this->assertEquals($this->config->getTimeout(), $expected); + } + + public function testGetPersistentIdentifier() + { + $expected = 'sess01'; + $this->deploymentConfig->expects($this->once()) + ->method('get') + ->with(Config::PARAM_PERSISTENT_IDENTIFIER) + ->willReturn($expected); + $this->assertEquals($this->config->getPersistentIdentifier(), $expected); + } + + public function testGetCompressionThreshold() + { + $expected = 2; + $this->deploymentConfig->expects($this->once()) + ->method('get') + ->with(Config::PARAM_COMPRESSION_THRESHOLD) + ->willReturn($expected); + $this->assertEquals($this->config->getCompressionThreshold(), $expected); + } + + public function testGetCompressionLibrary() + { + $expected = 'gzip'; + $this->deploymentConfig->expects($this->once()) + ->method('get') + ->with(Config::PARAM_COMPRESSION_LIBRARY) + ->willReturn($expected); + $this->assertEquals($this->config->getCompressionLibrary(), $expected); + } + + public function testGetMaxConcurrency() + { + $expected = 6; + $this->deploymentConfig->expects($this->once()) + ->method('get') + ->with(Config::PARAM_MAX_CONCURRENCY) + ->willReturn($expected); + $this->assertEquals($this->config->getMaxConcurrency(), $expected); + } + + public function testGetMaxLifetime() + { + $expected = 30; + $this->deploymentConfig->expects($this->once()) + ->method('get') + ->with(Config::PARAM_MAX_LIFETIME) + ->willReturn($expected); + $this->assertEquals($this->config->getMaxLifetime(), $expected); + } + + public function testGetMinLifetime() + { + $expected = 30; + $this->deploymentConfig->expects($this->once()) + ->method('get') + ->with(Config::PARAM_MIN_LIFETIME) + ->willReturn($expected); + $this->assertEquals($this->config->getMinLifetime(), $expected); + } + + public function testGetDisableLocking() + { + $expected = false; + $this->deploymentConfig->expects($this->once()) + ->method('get') + ->with(Config::PARAM_DISABLE_LOCKING) + ->willReturn($expected); + $this->assertEquals($this->config->getDisableLocking(), $expected); + } + + public function testGetBotLifetime() + { + $expected = 30; + $this->deploymentConfig->expects($this->once()) + ->method('get') + ->with(Config::PARAM_BOT_LIFETIME) + ->willReturn($expected); + $this->assertEquals($this->config->getBotLifetime(), $expected); + } + + public function testGetBotFirstLifetime() + { + $expected = 30; + $this->deploymentConfig->expects($this->once()) + ->method('get') + ->with(Config::PARAM_BOT_FIRST_LIFETIME) + ->willReturn($expected); + $this->assertEquals($this->config->getBotFirstLifetime(), $expected); + } + + public function testGetFirstLifetime() + { + $expected = 30; + $this->deploymentConfig->expects($this->once()) + ->method('get') + ->with(Config::PARAM_FIRST_LIFETIME) + ->willReturn($expected); + $this->assertEquals($this->config->getFirstLifetime(), $expected); + } + + public function testBreakAfter() + { + $areaCode = 'frontend'; + $breakAfter = 5; + $this->deploymentConfig->expects($this->once()) + ->method('get') + ->with(Config::PARAM_BREAK_AFTER . '_' . $areaCode) + ->willReturn($breakAfter); + $this->appState->expects($this->once()) + ->method('getAreaCode') + ->willReturn($areaCode); + $this->assertEquals($this->config->getBreakAfter(), $breakAfter); + } +} diff --git a/lib/internal/Magento/Framework/Session/Test/Unit/SaveHandler/Redis/LoggerTest.php b/lib/internal/Magento/Framework/Session/Test/Unit/SaveHandler/Redis/LoggerTest.php new file mode 100644 index 0000000000000000000000000000000000000000..d48bea62b542903620debc3c4f4a9babbd884f14 --- /dev/null +++ b/lib/internal/Magento/Framework/Session/Test/Unit/SaveHandler/Redis/LoggerTest.php @@ -0,0 +1,95 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Session\Test\Unit\SaveHandler\Redis; + +use Cm\RedisSession\Handler\LoggerInterface; +use Magento\Framework\Session\SaveHandler\Redis\Logger; + +class LoggerTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var \Cm\RedisSession\Handler\ConfigInterface + */ + protected $config; + + /** + * @var \Psr\Log\LoggerInterface + */ + protected $psrLogger; + + /** + * @var \Magento\Framework\Session\SaveHandler\Redis\Logger + */ + protected $logger; + + /** + * @var \Magento\Framework\App\Request\Http + */ + protected $request; + + /** + * @var string + */ + protected $requestUri = 'customer/account/login'; + + public function setUp() + { + $this->config = $this->getMock('Cm\RedisSession\Handler\ConfigInterface', [], [], '', false); + $this->config->expects($this->once()) + ->method('getLogLevel') + ->willReturn(LoggerInterface::DEBUG); + $this->psrLogger = $this->getMock('Psr\Log\LoggerInterface', [], [], '', false); + $this->request = $this->getMock('Magento\Framework\App\Request\Http', [], [], '', false); + //$this->logger = new Logger($this->config, $this->psrLogger, $this->request); + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->logger = $objectManager->getObject( + 'Magento\Framework\Session\SaveHandler\Redis\Logger', + [ + 'config' => $this->config, + 'logger' => $this->psrLogger, + 'request' => $this->request + ] + ); + } + + /** + * @dataProvider logDataProvider + */ + public function testLog($logLevel, $method) + { + $message = 'Error message'; + $this->request->expects($this->once()) + ->method('getRequestUri') + ->willReturn($this->requestUri); + $this->psrLogger->expects($this->once()) + ->method($method) + ->with($message . ' ' . $this->requestUri); + $this->logger->log($message, $logLevel); + } + + public function logDataProvider() + { + return [ + [LoggerInterface::EMERGENCY, 'emergency'], + [LoggerInterface::ALERT, 'alert'], + [LoggerInterface::CRITICAL, 'critical'], + [LoggerInterface::ERROR, 'error'], + [LoggerInterface::WARNING, 'warning'], + [LoggerInterface::NOTICE, 'notice'], + [LoggerInterface::INFO, 'info'], + [LoggerInterface::DEBUG, 'debug'], + ]; + } + + public function testLogException() + { + $exception = new \Exception('Error message'); + $this->psrLogger->expects($this->once()) + ->method('critical') + ->with($exception->getMessage()); + $this->logger->logException($exception); + } +} diff --git a/lib/internal/Magento/Framework/TestFramework/Unit/Helper/SelectRendererTrait.php b/lib/internal/Magento/Framework/TestFramework/Unit/Helper/SelectRendererTrait.php index 8089f288c3c7211da352a1b5d1450f539c922265..24d160d07d3dbdc8c22f7c0e7c8f0053e1be2f12 100644 --- a/lib/internal/Magento/Framework/TestFramework/Unit/Helper/SelectRendererTrait.php +++ b/lib/internal/Magento/Framework/TestFramework/Unit/Helper/SelectRendererTrait.php @@ -26,6 +26,7 @@ trait SelectRendererTrait 'Magento\Framework\DB\Select\DistinctRenderer' ), 'sort' => 11, + 'part' => 'distinct', ], 'columns' => [ 'renderer' => $objectManager->getObject( @@ -35,12 +36,14 @@ trait SelectRendererTrait ] ), 'sort' => 11, + 'part' => 'columns', ], 'union' => [ 'renderer' => $objectManager->getObject( 'Magento\Framework\DB\Select\UnionRenderer' ), 'sort' => 11, + 'part' => 'union', ], 'from' => [ 'renderer' => $objectManager->getObject( @@ -50,36 +53,42 @@ trait SelectRendererTrait ] ), 'sort' => 11, + 'part' => 'from', ], 'where' => [ 'renderer' => $objectManager->getObject( 'Magento\Framework\DB\Select\WhereRenderer' ), 'sort' => 11, + 'part' => 'where', ], 'group' => [ 'renderer' => $objectManager->getObject( 'Magento\Framework\DB\Select\GroupRenderer' ), 'sort' => 11, + 'part' => 'group', ], 'having' => [ 'renderer' => $objectManager->getObject( 'Magento\Framework\DB\Select\HavingRenderer' ), 'sort' => 11, + 'part' => 'having', ], 'order' => [ 'renderer' => $objectManager->getObject( 'Magento\Framework\DB\Select\OrderRenderer' ), 'sort' => 11, + 'part' => 'order', ], 'limit' => [ 'renderer' => $objectManager->getObject( 'Magento\Framework\DB\Select\LimitRenderer' ), 'sort' => 11, + 'part' => 'limitcount', ], ], ] diff --git a/setup/src/Magento/Setup/Test/Unit/Module/ConfigOptionsListTest.php b/setup/src/Magento/Setup/Test/Unit/Model/ConfigOptionsListTest.php similarity index 99% rename from setup/src/Magento/Setup/Test/Unit/Module/ConfigOptionsListTest.php rename to setup/src/Magento/Setup/Test/Unit/Model/ConfigOptionsListTest.php index 27454c09f6177b71a63d6c01ca92703eb16f10b5..f3f55090dee5eeec5f829d16613c36d2d8749aff 100644 --- a/setup/src/Magento/Setup/Test/Unit/Module/ConfigOptionsListTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Model/ConfigOptionsListTest.php @@ -4,7 +4,7 @@ * See COPYING.txt for license details. */ -namespace Magento\Setup\Test\Unit\Module; +namespace Magento\Setup\Test\Unit\Model; use Magento\Setup\Model\ConfigGenerator; use Magento\Setup\Model\ConfigOptionsList; @@ -149,7 +149,7 @@ class ConfigOptionsListTest extends \PHPUnit_Framework_TestCase $this->dbValidator->expects($this->once())->method('checkDatabaseTablePrefix')->willReturn($configDataMock); $this->dbValidator->expects($this->once())->method('checkDatabaseConnection')->willReturn($configDataMock); } - + /** * @param string $hosts * @param bool $expectedError