diff --git a/.travis.yml b/.travis.yml
index 95eb5ecb62bca..74e374412fff4 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -9,7 +9,7 @@ addons:
- postfix
language: php
php:
- - 5.6
+ - 5.6.29
- 7.0
env:
global:
diff --git a/app/code/Magento/Captcha/Test/Unit/Helper/DataTest.php b/app/code/Magento/Captcha/Test/Unit/Helper/DataTest.php
index 93379cff52f2c..40558b3cae8a5 100644
--- a/app/code/Magento/Captcha/Test/Unit/Helper/DataTest.php
+++ b/app/code/Magento/Captcha/Test/Unit/Helper/DataTest.php
@@ -53,10 +53,6 @@ protected function setUp()
*/
public function testGetCaptcha()
{
- if (!function_exists("imageftbbox")) {
- $this->markTestSkipped('imageftbbox is not available on the test environment');
- }
-
$this->configMock->expects(
$this->once()
)->method(
diff --git a/app/code/Magento/Captcha/Test/Unit/Model/DefaultTest.php b/app/code/Magento/Captcha/Test/Unit/Model/DefaultTest.php
index 26984af3df32c..649bce192614b 100644
--- a/app/code/Magento/Captcha/Test/Unit/Model/DefaultTest.php
+++ b/app/code/Magento/Captcha/Test/Unit/Model/DefaultTest.php
@@ -88,9 +88,6 @@ class DefaultTest extends \PHPUnit_Framework_TestCase
*/
protected function setUp()
{
- if (!function_exists("imageftbbox")) {
- $this->markTestSkipped('imageftbbox is not available on the test environment');
- }
$this->session = $this->_getSessionStub();
$this->_storeManager = $this->getMock(
diff --git a/app/code/Magento/Catalog/Model/Indexer/Category/Product/AbstractAction.php b/app/code/Magento/Catalog/Model/Indexer/Category/Product/AbstractAction.php
index c4d8e4fd9be34..3a6f833a5a09c 100644
--- a/app/code/Magento/Catalog/Model/Indexer/Category/Product/AbstractAction.php
+++ b/app/code/Magento/Catalog/Model/Indexer/Category/Product/AbstractAction.php
@@ -8,6 +8,8 @@
namespace Magento\Catalog\Model\Indexer\Category\Product;
+use Magento\Framework\DB\Query\BatchIteratorInterface as BatchIteratorInterface;
+use Magento\Framework\DB\Query\Generator as QueryGenerator;
use Magento\Framework\App\ResourceConnection;
use Magento\Framework\EntityManager\MetadataPool;
@@ -102,20 +104,29 @@ abstract class AbstractAction
*/
protected $tempTreeIndexTableName;
+ /**
+ * @var QueryGenerator
+ */
+ private $queryGenerator;
+
/**
* @param ResourceConnection $resource
* @param \Magento\Store\Model\StoreManagerInterface $storeManager
* @param \Magento\Catalog\Model\Config $config
+ * @param QueryGenerator $queryGenerator
*/
public function __construct(
\Magento\Framework\App\ResourceConnection $resource,
\Magento\Store\Model\StoreManagerInterface $storeManager,
- \Magento\Catalog\Model\Config $config
+ \Magento\Catalog\Model\Config $config,
+ QueryGenerator $queryGenerator = null
) {
$this->resource = $resource;
$this->connection = $resource->getConnection();
$this->storeManager = $storeManager;
$this->config = $config;
+ $this->queryGenerator = $queryGenerator ?: \Magento\Framework\App\ObjectManager::getInstance()
+ ->get(QueryGenerator::class);
}
/**
@@ -309,15 +320,26 @@ protected function isRangingNeeded()
* @param int $range
* @return \Magento\Framework\DB\Select[]
*/
- protected function prepareSelectsByRange(\Magento\Framework\DB\Select $select, $field, $range = self::RANGE_CATEGORY_STEP)
- {
- return $this->isRangingNeeded() ? $this->connection->selectsByRange(
- $field,
- $select,
- $range
- ) : [
- $select
- ];
+ protected function prepareSelectsByRange(
+ \Magento\Framework\DB\Select $select,
+ $field,
+ $range = self::RANGE_CATEGORY_STEP
+ ) {
+ if($this->isRangingNeeded()) {
+ $iterator = $this->queryGenerator->generate(
+ $field,
+ $select,
+ $range,
+ \Magento\Framework\DB\Query\BatchIteratorInterface::NON_UNIQUE_FIELD_ITERATOR
+ );
+
+ $queries = [];
+ foreach ($iterator as $query) {
+ $queries[] = $query;
+ }
+ return $queries;
+ }
+ return [$select];
}
/**
diff --git a/app/code/Magento/Catalog/Model/ProductLink/CollectionProvider.php b/app/code/Magento/Catalog/Model/ProductLink/CollectionProvider.php
index 917a47b637cea..eb4e385993ac2 100644
--- a/app/code/Magento/Catalog/Model/ProductLink/CollectionProvider.php
+++ b/app/code/Magento/Catalog/Model/ProductLink/CollectionProvider.php
@@ -48,9 +48,21 @@ public function getCollection(\Magento\Catalog\Model\Product $product, $type)
$products = $this->providers[$type]->getLinkedProducts($product);
$converter = $this->converterPool->getConverter($type);
$output = [];
+ $sorterItems = [];
foreach ($products as $item) {
$output[$item->getId()] = $converter->convert($item);
}
- return $output;
+
+ foreach ($output as $item) {
+ $itemPosition = $item['position'];
+ if (!isset($sorterItems[$itemPosition])) {
+ $sorterItems[$itemPosition] = $item;
+ } else {
+ $newPosition = $itemPosition + 1;
+ $sorterItems[$newPosition] = $item;
+ }
+ }
+ ksort($sorterItems);
+ return $sorterItems;
}
}
diff --git a/app/code/Magento/Catalog/Test/Unit/Model/CollectionProviderTest.php b/app/code/Magento/Catalog/Test/Unit/Model/CollectionProviderTest.php
new file mode 100644
index 0000000000000..b543c92ac0875
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Unit/Model/CollectionProviderTest.php
@@ -0,0 +1,110 @@
+productMock = $this->getMock(Product::class, [], [], '', false, false);
+ $this->converterPoolMock = $this->getMock(ConverterPool::class, [], [], '', false, false);
+ $this->providerMock = $this->getMock(CollectionProviderInterface::class);
+ $this->converterMock = $this->getMock(ConverterInterface::class);
+
+ $this->model = new CollectionProvider($this->converterPoolMock, ['crosssell' => $this->providerMock]);
+ }
+
+ /**
+ * Test sort order of linked products based on configured item position.
+ */
+ public function testGetCollection()
+ {
+ $linkedProductOneMock = $this->getMock(Product::class, [], [], '', false, false);
+ $linkedProductTwoMock = $this->getMock(Product::class, [], [], '', false, false);
+ $linkedProductThreeMock = $this->getMock(Product::class, [], [], '', false, false);
+
+ $linkedProductOneMock->expects($this->once())->method('getId')->willReturn(1);
+ $linkedProductTwoMock->expects($this->once())->method('getId')->willReturn(2);
+ $linkedProductThreeMock->expects($this->once())->method('getId')->willReturn(3);
+
+ $this->converterPoolMock->expects($this->once())
+ ->method('getConverter')
+ ->with('crosssell')
+ ->willReturn($this->converterMock);
+
+ $map = [
+ [$linkedProductOneMock, ['name' => 'Product One', 'position' => 10]],
+ [$linkedProductTwoMock, ['name' => 'Product Two', 'position' => 2]],
+ [$linkedProductThreeMock, ['name' => 'Product Three', 'position' => 2]],
+ ];
+
+ $this->converterMock->expects($this->exactly(3))->method('convert')->willReturnMap($map);
+
+ $this->providerMock->expects($this->once())
+ ->method('getLinkedProducts')
+ ->with($this->productMock)
+ ->willReturn(
+ [
+ $linkedProductOneMock,
+ $linkedProductTwoMock,
+ $linkedProductThreeMock
+ ]
+ );
+
+ $expectedResult = [
+ 2 => ['name' => 'Product Two', 'position' => 2],
+ 3 => ['name' => 'Product Three', 'position' => 2],
+ 10 => ['name' => 'Product One', 'position' => 10],
+ ];
+
+ $actualResult = $this->model->getCollection($this->productMock, 'crosssell');
+
+ $this->assertEquals($expectedResult, $actualResult, 'Sort order of linked products in incorrect');
+ }
+
+ /**
+ * Test exception when collection provider is not configured for product link type.
+ *
+ * @expectedException \Magento\Framework\Exception\NoSuchEntityException
+ * @expectedExceptionMessage Collection provider is not registered
+ */
+ public function testGetCollectionWithMissingProviders()
+ {
+ $this->model->getCollection($this->productMock, 'upsell');
+ }
+}
diff --git a/app/code/Magento/Catalog/etc/eav_attributes.xml b/app/code/Magento/Catalog/etc/eav_attributes.xml
index 133849a28e048..005402937232f 100644
--- a/app/code/Magento/Catalog/etc/eav_attributes.xml
+++ b/app/code/Magento/Catalog/etc/eav_attributes.xml
@@ -30,6 +30,7 @@
+
diff --git a/app/code/Magento/Cms/Block/Adminhtml/Wysiwyg/Images/Tree.php b/app/code/Magento/Cms/Block/Adminhtml/Wysiwyg/Images/Tree.php
index 1b5e4f54f552c..7e52e2bdb4702 100644
--- a/app/code/Magento/Cms/Block/Adminhtml/Wysiwyg/Images/Tree.php
+++ b/app/code/Magento/Cms/Block/Adminhtml/Wysiwyg/Images/Tree.php
@@ -26,20 +26,30 @@ class Tree extends \Magento\Backend\Block\Template
*/
protected $_cmsWysiwygImages = null;
+ /**
+ * @var \Magento\Framework\Serialize\Serializer\Json
+ */
+ private $serializer;
+
/**
* @param \Magento\Backend\Block\Template\Context $context
* @param \Magento\Cms\Helper\Wysiwyg\Images $cmsWysiwygImages
* @param \Magento\Framework\Registry $registry
* @param array $data
+ * @param \Magento\Framework\Serialize\Serializer\Json|null $serializer
+ * @throws \RuntimeException
*/
public function __construct(
\Magento\Backend\Block\Template\Context $context,
\Magento\Cms\Helper\Wysiwyg\Images $cmsWysiwygImages,
\Magento\Framework\Registry $registry,
- array $data = []
+ array $data = [],
+ \Magento\Framework\Serialize\Serializer\Json $serializer = null
) {
$this->_coreRegistry = $registry;
$this->_cmsWysiwygImages = $cmsWysiwygImages;
+ $this->serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance()
+ ->get(\Magento\Framework\Serialize\Serializer\Json::class);
parent::__construct($context, $data);
}
@@ -65,7 +75,7 @@ public function getTreeJson()
'cls' => 'folder',
];
}
- return \Zend_Json::encode($jsonArray);
+ return $this->serializer->serialize($jsonArray);
}
/**
diff --git a/app/code/Magento/Customer/Block/Account/AuthenticationPopup.php b/app/code/Magento/Customer/Block/Account/AuthenticationPopup.php
index a0f94e1b8f733..eefec4c35679c 100644
--- a/app/code/Magento/Customer/Block/Account/AuthenticationPopup.php
+++ b/app/code/Magento/Customer/Block/Account/AuthenticationPopup.php
@@ -15,16 +15,26 @@ class AuthenticationPopup extends \Magento\Framework\View\Element\Template
*/
protected $jsLayout;
+ /**
+ * @var \Magento\Framework\Serialize\Serializer\Json
+ */
+ private $serializer;
+
/**
* @param \Magento\Framework\View\Element\Template\Context $context
* @param array $data
+ * @param \Magento\Framework\Serialize\Serializer\Json|null $serializer
+ * @throws \RuntimeException
*/
public function __construct(
\Magento\Framework\View\Element\Template\Context $context,
- array $data = []
+ array $data = [],
+ \Magento\Framework\Serialize\Serializer\Json $serializer = null
) {
parent::__construct($context, $data);
$this->jsLayout = isset($data['jsLayout']) && is_array($data['jsLayout']) ? $data['jsLayout'] : [];
+ $this->serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance()
+ ->get(\Magento\Framework\Serialize\Serializer\Json::class);
}
/**
@@ -32,7 +42,7 @@ public function __construct(
*/
public function getJsLayout()
{
- return \Zend_Json::encode($this->jsLayout);
+ return $this->serializer->serialize($this->jsLayout);
}
/**
@@ -50,6 +60,18 @@ public function getConfig()
];
}
+ /**
+ * Returns popup config in JSON format.
+ *
+ * Added in scope of https://github.com/magento/magento2/pull/8617
+ *
+ * @return bool|string
+ */
+ public function getSerializedConfig()
+ {
+ return $this->serializer->serialize($this->getConfig());
+ }
+
/**
* Is autocomplete enabled for storefront
*
diff --git a/app/code/Magento/Customer/Test/Unit/Block/Account/AuthenticationPopupTest.php b/app/code/Magento/Customer/Test/Unit/Block/Account/AuthenticationPopupTest.php
index 67a3fb8f3a576..40f770ab9fbd4 100644
--- a/app/code/Magento/Customer/Test/Unit/Block/Account/AuthenticationPopupTest.php
+++ b/app/code/Magento/Customer/Test/Unit/Block/Account/AuthenticationPopupTest.php
@@ -31,6 +31,9 @@ class AuthenticationPopupTest extends \PHPUnit_Framework_TestCase
/** @var UrlInterface|\PHPUnit_Framework_MockObject_MockObject */
private $urlBuilderMock;
+ /** @var \Magento\Framework\Serialize\Serializer\Json|\PHPUnit_Framework_MockObject_MockObject */
+ private $serializerMock;
+
protected function setUp()
{
$this->contextMock = $this->getMockBuilder(Context::class)
@@ -72,8 +75,13 @@ function ($string) {
->method('getEscaper')
->willReturn($escaperMock);
+ $this->serializerMock = $this->getMockBuilder(\Magento\Framework\Serialize\Serializer\Json::class)
+ ->getMock();
+
$this->model = new AuthenticationPopup(
- $this->contextMock
+ $this->contextMock,
+ [],
+ $this->serializerMock
);
}
@@ -83,6 +91,7 @@ function ($string) {
* @param string $registerUrl
* @param string $forgotUrl
* @param array $result
+ * @throws \PHPUnit_Framework_Exception
*
* @dataProvider dataProviderGetConfig
*/
@@ -172,4 +181,51 @@ public function dataProviderGetConfig()
],
];
}
+
+ /**
+ * @param mixed $isAutocomplete
+ * @param string $baseUrl
+ * @param string $registerUrl
+ * @param string $forgotUrl
+ * @param array $result
+ * @throws \PHPUnit_Framework_Exception
+ *
+ * @dataProvider dataProviderGetConfig
+ */
+ public function testGetSerializedConfig($isAutocomplete, $baseUrl, $registerUrl, $forgotUrl, array $result)
+ {
+ $this->scopeConfigMock->expects($this->any())
+ ->method('getValue')
+ ->with(Form::XML_PATH_ENABLE_AUTOCOMPLETE, ScopeInterface::SCOPE_STORE, null)
+ ->willReturn($isAutocomplete);
+
+ /** @var StoreInterface||\PHPUnit_Framework_MockObject_MockObject $storeMock */
+ $storeMock = $this->getMockBuilder(StoreInterface::class)
+ ->setMethods(['getBaseUrl'])
+ ->getMockForAbstractClass();
+
+ $this->storeManagerMock->expects($this->any())
+ ->method('getStore')
+ ->with(null)
+ ->willReturn($storeMock);
+
+ $storeMock->expects($this->any())
+ ->method('getBaseUrl')
+ ->willReturn($baseUrl);
+
+ $this->urlBuilderMock->expects($this->any())
+ ->method('getUrl')
+ ->willReturnMap(
+ [
+ ['customer/account/create', [], $registerUrl],
+ ['customer/account/forgotpassword', [], $forgotUrl],
+ ]
+ );
+ $this->serializerMock->expects($this->any())->method('serialize')
+ ->willReturn(
+ json_encode($this->model->getConfig())
+ );
+
+ $this->assertEquals(json_encode($result), $this->model->getSerializedConfig());
+ }
}
diff --git a/app/code/Magento/Customer/view/frontend/templates/account/authentication-popup.phtml b/app/code/Magento/Customer/view/frontend/templates/account/authentication-popup.phtml
index bcf0cc92bc912..20ea488931398 100644
--- a/app/code/Magento/Customer/view/frontend/templates/account/authentication-popup.phtml
+++ b/app/code/Magento/Customer/view/frontend/templates/account/authentication-popup.phtml
@@ -10,7 +10,7 @@
?>