Skip to content

Commit 658e754

Browse files
authored
Merge pull request #1269 from magento-tsg/2.1.8-develop-pr21
[TSG] Backporting for 2.1 (pr21) (2.1.8)
2 parents ca53c80 + 47796ad commit 658e754

File tree

84 files changed

+7187
-851
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

84 files changed

+7187
-851
lines changed

app/code/Magento/Catalog/Controller/Adminhtml/Category.php

+20-8
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,16 @@ abstract class Category extends \Magento\Backend\App\Action
3131
*/
3232
protected function _initCategory($getRootInstead = false)
3333
{
34-
$categoryId = (int)$this->getRequest()->getParam('id', false);
34+
$categoryId = $this->resolveCategoryId();
3535
$storeId = (int)$this->getRequest()->getParam('store');
36-
$category = $this->_objectManager->create('Magento\Catalog\Model\Category');
36+
$category = $this->_objectManager->create(\Magento\Catalog\Model\Category::class);
3737
$category->setStoreId($storeId);
3838

3939
if ($categoryId) {
4040
$category->load($categoryId);
4141
if ($storeId) {
4242
$rootId = $this->_objectManager->get(
43-
'Magento\Store\Model\StoreManagerInterface'
43+
\Magento\Store\Model\StoreManagerInterface::class
4444
)->getStore(
4545
$storeId
4646
)->getRootCategoryId();
@@ -55,13 +55,25 @@ protected function _initCategory($getRootInstead = false)
5555
}
5656
}
5757

58-
$this->_objectManager->get('Magento\Framework\Registry')->register('category', $category);
59-
$this->_objectManager->get('Magento\Framework\Registry')->register('current_category', $category);
60-
$this->_objectManager->get('Magento\Cms\Model\Wysiwyg\Config')
58+
$this->_objectManager->get(\Magento\Framework\Registry::class)->register('category', $category);
59+
$this->_objectManager->get(\Magento\Framework\Registry::class)->register('current_category', $category);
60+
$this->_objectManager->get(\Magento\Cms\Model\Wysiwyg\Config::class)
6161
->setStoreId($this->getRequest()->getParam('store'));
6262
return $category;
6363
}
6464

65+
/**
66+
* Resolve Category Id (from get or from post).
67+
*
68+
* @return int
69+
*/
70+
private function resolveCategoryId()
71+
{
72+
$categoryId = (int)$this->getRequest()->getParam('id', false);
73+
74+
return $categoryId ?: (int)$this->getRequest()->getParam('entity_id', false);
75+
}
76+
6577
/**
6678
* Build response for ajax request
6779
*
@@ -79,7 +91,7 @@ protected function ajaxRequestResponse($category, $resultPage)
7991
if (empty($breadcrumbsPath)) {
8092
// but if no category, and it is deleted - prepare breadcrumbs from path, saved in session
8193
$breadcrumbsPath = $this->_objectManager->get(
82-
'Magento\Backend\Model\Auth\Session'
94+
\Magento\Backend\Model\Auth\Session::class
8395
)->getDeletedPath(
8496
true
8597
);
@@ -107,7 +119,7 @@ protected function ajaxRequestResponse($category, $resultPage)
107119
['response' => $eventResponse, 'controller' => $this]
108120
);
109121
/** @var \Magento\Framework\Controller\Result\Json $resultJson */
110-
$resultJson = $this->_objectManager->get('Magento\Framework\Controller\Result\Json');
122+
$resultJson = $this->_objectManager->get(\Magento\Framework\Controller\Result\Json::class);
111123
$resultJson->setHeader('Content-type', 'application/json', true);
112124
$resultJson->setData($eventResponse->getData());
113125
return $resultJson;

app/code/Magento/Catalog/Model/ResourceModel/Category.php

+32-18
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,13 @@ class Category extends AbstractResource
3333
*/
3434
protected $_categoryProductTable;
3535

36+
/**
37+
* Entities where attribute is filled.
38+
*
39+
* @var array[]
40+
*/
41+
private $entitiesWhereAttributesIs;
42+
3643
/**
3744
* Id of 'is_active' category attribute
3845
*
@@ -575,22 +582,29 @@ public function getIsActiveAttributeId()
575582
*/
576583
public function findWhereAttributeIs($entityIdsFilter, $attribute, $expectedValue)
577584
{
578-
$linkField = $this->getLinkField();
579-
$bind = ['attribute_id' => $attribute->getId(), 'value' => $expectedValue];
580-
$selectEntities = $this->getConnection()->select()->from(
581-
['ce' => $this->getTable('catalog_category_entity')],
582-
['entity_id']
583-
)->joinLeft(
584-
['ci' => $attribute->getBackend()->getTable()],
585-
"ci.{$linkField} = ce.{$linkField} AND attribute_id = :attribute_id",
586-
['value']
587-
)->where(
588-
'ci.value = :value'
589-
)->where(
590-
'ce.entity_id IN (?)',
591-
$entityIdsFilter
592-
);
593-
return $this->getConnection()->fetchCol($selectEntities, $bind);
585+
$entityIdsFilterHash = md5(serialize($entityIdsFilter));
586+
587+
if (!isset($this->entitiesWhereAttributesIs[$entityIdsFilterHash][$attribute->getId()][$expectedValue])) {
588+
$linkField = $this->getLinkField();
589+
$bind = ['attribute_id' => $attribute->getId(), 'value' => $expectedValue];
590+
$selectEntities = $this->getConnection()->select()->from(
591+
['ce' => $this->getTable('catalog_category_entity')],
592+
['entity_id']
593+
)->joinLeft(
594+
['ci' => $attribute->getBackend()->getTable()],
595+
"ci.{$linkField} = ce.{$linkField} AND attribute_id = :attribute_id",
596+
['value']
597+
)->where(
598+
'ci.value = :value'
599+
)->where(
600+
'ce.entity_id IN (?)',
601+
$entityIdsFilter
602+
);
603+
$this->entitiesWhereAttributesIs[$entityIdsFilterHash][$attribute->getId()][$expectedValue] =
604+
$this->getConnection()->fetchCol($selectEntities, $bind);
605+
}
606+
607+
return $this->entitiesWhereAttributesIs[$entityIdsFilterHash][$attribute->getId()][$expectedValue];
594608
}
595609

596610
/**
@@ -1035,7 +1049,7 @@ private function getEntityManager()
10351049
{
10361050
if (null === $this->entityManager) {
10371051
$this->entityManager = \Magento\Framework\App\ObjectManager::getInstance()
1038-
->get('Magento\Framework\EntityManager\EntityManager');
1052+
->get(\Magento\Framework\EntityManager\EntityManager::class);
10391053
}
10401054
return $this->entityManager;
10411055
}
@@ -1047,7 +1061,7 @@ private function getAggregateCount()
10471061
{
10481062
if (null === $this->aggregateCount) {
10491063
$this->aggregateCount = \Magento\Framework\App\ObjectManager::getInstance()
1050-
->get('Magento\Catalog\Model\ResourceModel\Category\AggregateCount');
1064+
->get(\Magento\Catalog\Model\ResourceModel\Category\AggregateCount::class);
10511065
}
10521066
return $this->aggregateCount;
10531067
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
<?php
2+
/**
3+
* Copyright © 2013-2017 Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
namespace Magento\Catalog\Test\Unit\Model\ResourceModel;
8+
9+
use Magento\Catalog\Model\Factory;
10+
use Magento\Catalog\Model\ResourceModel\Category;
11+
use Magento\Catalog\Model\ResourceModel\Category\CollectionFactory;
12+
use Magento\Eav\Model\Config;
13+
use Magento\Eav\Model\Entity\Attribute;
14+
use Magento\Eav\Model\Entity\Attribute\Backend\AbstractBackend;
15+
use Magento\Eav\Model\Entity\Context;
16+
use Magento\Eav\Model\Entity\Type;
17+
use Magento\Framework\App\ResourceConnection;
18+
use Magento\Framework\DB\Adapter\AdapterInterface as Adapter;
19+
use Magento\Framework\DB\Select;
20+
use Magento\Framework\Event\ManagerInterface;
21+
use Magento\Store\Model\StoreManagerInterface;
22+
23+
/**
24+
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
25+
*/
26+
class CategoryTest extends \PHPUnit_Framework_TestCase
27+
{
28+
/**
29+
* @var Category
30+
*/
31+
protected $category;
32+
33+
/**
34+
* @var Context|\PHPUnit_Framework_MockObject_MockObject
35+
*/
36+
protected $contextMock;
37+
38+
/**
39+
* @var Select|\PHPUnit_Framework_MockObject_MockObject
40+
*/
41+
private $selectMock;
42+
43+
/**
44+
* @var Adapter|\PHPUnit_Framework_MockObject_MockObject
45+
*/
46+
private $connectionMock;
47+
48+
/**
49+
* @var ResourceConnection|\PHPUnit_Framework_MockObject_MockObject
50+
*/
51+
private $resourceMock;
52+
53+
/**
54+
* @var Config|\PHPUnit_Framework_MockObject_MockObject
55+
*/
56+
private $eavConfigMock;
57+
58+
/**
59+
* @var Type|\PHPUnit_Framework_MockObject_MockObject
60+
*/
61+
private $entityType;
62+
63+
/**
64+
* @var StoreManagerInterface|\PHPUnit_Framework_MockObject_MockObject
65+
*/
66+
protected $storeManagerMock;
67+
68+
/**
69+
* @var Factory|\PHPUnit_Framework_MockObject_MockObject
70+
*/
71+
protected $factoryMock;
72+
73+
/**
74+
* @var ManagerInterface|\PHPUnit_Framework_MockObject_MockObject
75+
*/
76+
protected $managerMock;
77+
78+
/**
79+
* @var Category\TreeFactory|\PHPUnit_Framework_MockObject_MockObject
80+
*/
81+
protected $treeFactoryMock;
82+
83+
/**
84+
* @var CollectionFactory|\PHPUnit_Framework_MockObject_MockObject
85+
*/
86+
protected $collectionFactoryMock;
87+
88+
/**
89+
* {@inheritDoc}
90+
*/
91+
protected function setUp()
92+
{
93+
$this->selectMock = $this->getMockBuilder(Select::class)->disableOriginalConstructor()->getMock();
94+
$this->selectMock->expects($this->at(2))->method('where')->willReturnSelf();
95+
$this->selectMock->expects($this->once())->method('from')->willReturnSelf();
96+
$this->selectMock->expects($this->once())->method('joinLeft')->willReturnSelf();
97+
$this->connectionMock = $this->getMockBuilder(Adapter::class)->getMockForAbstractClass();
98+
$this->connectionMock->expects($this->once())->method('select')->willReturn($this->selectMock);
99+
$this->resourceMock = $this->getMockBuilder(ResourceConnection::class)->disableOriginalConstructor()->getMock();
100+
$this->resourceMock->expects($this->any())->method('getConnection')->willReturn($this->connectionMock);
101+
$this->connectionMock->expects($this->any())->method('getTableName')->willReturn('TableName');
102+
$this->resourceMock->expects($this->any())->method('getTableName')->willReturn('TableName');
103+
$this->contextMock = $this->getMockBuilder(Context::class)->disableOriginalConstructor()->getMock();
104+
$this->eavConfigMock = $this->getMockBuilder(Config::class)->disableOriginalConstructor()->getMock();
105+
$this->entityType = $this->getMockBuilder(Type::class)->disableOriginalConstructor()->getMock();
106+
$this->eavConfigMock->expects($this->any())->method('getEntityType')->willReturn($this->entityType);
107+
$this->contextMock->expects($this->any())->method('getEavConfig')->willReturn($this->eavConfigMock);
108+
$this->contextMock->expects($this->any())->method('getResource')->willReturn($this->resourceMock);
109+
$this->storeManagerMock = $this->getMockBuilder(StoreManagerInterface::class)->getMock();
110+
$this->factoryMock = $this->getMockBuilder(Factory::class)->disableOriginalConstructor()->getMock();
111+
$this->managerMock = $this->getMockBuilder(ManagerInterface::class)->getMock();
112+
$this->treeFactoryMock = $this->getMockBuilder(Category\TreeFactory::class)
113+
->disableOriginalConstructor()
114+
->getMock();
115+
$this->collectionFactoryMock = $this->getMockBuilder(CollectionFactory::class)
116+
->disableOriginalConstructor()
117+
->getMock();
118+
119+
$this->category = new Category(
120+
$this->contextMock,
121+
$this->storeManagerMock,
122+
$this->factoryMock,
123+
$this->managerMock,
124+
$this->treeFactoryMock,
125+
$this->collectionFactoryMock,
126+
[]
127+
);
128+
}
129+
130+
/**
131+
* @return void
132+
*/
133+
public function testFindWhereAttributeIs()
134+
{
135+
$entityIdsFilter = [1, 2];
136+
$expectedValue = 123;
137+
$attribute = $this->getMockBuilder(Attribute::class)->disableOriginalConstructor()->getMock();
138+
$backendModel = $this->getMockBuilder(AbstractBackend::class)->disableOriginalConstructor()->getMock();
139+
140+
$attribute->expects($this->any())->method('getBackend')->willReturn($backendModel);
141+
$this->connectionMock->expects($this->once())->method('fetchCol')->willReturn(['result']);
142+
143+
$result = $this->category->findWhereAttributeIs($entityIdsFilter, $attribute, $expectedValue);
144+
$this->assertEquals(['result'], $result);
145+
}
146+
}

app/code/Magento/CatalogUrlRewrite/Model/Category/ChildrenUrlRewriteGenerator.php

+26-8
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77

88
use Magento\Catalog\Model\Category;
99
use Magento\CatalogUrlRewrite\Model\CategoryUrlRewriteGeneratorFactory;
10+
use Magento\CatalogUrlRewrite\Model\CategoryUrlRewriteGenerator;
11+
use Magento\UrlRewrite\Model\MergeDataProviderFactory;
12+
use Magento\Framework\App\ObjectManager;
1013

1114
class ChildrenUrlRewriteGenerator
1215
{
@@ -16,36 +19,51 @@ class ChildrenUrlRewriteGenerator
1619
/** @var \Magento\CatalogUrlRewrite\Model\CategoryUrlRewriteGeneratorFactory */
1720
protected $categoryUrlRewriteGeneratorFactory;
1821

22+
/**
23+
* Container for new generated url rewrites.
24+
*
25+
* @var \Magento\UrlRewrite\Model\MergeDataProvider
26+
*/
27+
private $mergeDataProviderPrototype;
28+
1929
/**
2030
* @param \Magento\CatalogUrlRewrite\Model\Category\ChildrenCategoriesProvider $childrenCategoriesProvider
2131
* @param \Magento\CatalogUrlRewrite\Model\CategoryUrlRewriteGeneratorFactory $categoryUrlRewriteGeneratorFactory
32+
* @param \Magento\UrlRewrite\Model\MergeDataProviderFactory|null $mergeDataProviderFactory
2233
*/
2334
public function __construct(
2435
ChildrenCategoriesProvider $childrenCategoriesProvider,
25-
CategoryUrlRewriteGeneratorFactory $categoryUrlRewriteGeneratorFactory
36+
CategoryUrlRewriteGeneratorFactory $categoryUrlRewriteGeneratorFactory,
37+
MergeDataProviderFactory $mergeDataProviderFactory = null
2638
) {
2739
$this->childrenCategoriesProvider = $childrenCategoriesProvider;
2840
$this->categoryUrlRewriteGeneratorFactory = $categoryUrlRewriteGeneratorFactory;
41+
if (!isset($mergeDataProviderFactory)) {
42+
$mergeDataProviderFactory = ObjectManager::getInstance()->get(MergeDataProviderFactory::class);
43+
}
44+
$this->mergeDataProviderPrototype = $mergeDataProviderFactory->create();
2945
}
3046

3147
/**
3248
* Generate list of children urls
3349
*
3450
* @param int $storeId
3551
* @param \Magento\Catalog\Model\Category $category
52+
* @param int|null $rootCategoryId
3653
* @return \Magento\UrlRewrite\Service\V1\Data\UrlRewrite[]
3754
*/
38-
public function generate($storeId, Category $category)
55+
public function generate($storeId, Category $category, $rootCategoryId = null)
3956
{
40-
$urls = [];
41-
foreach ($this->childrenCategoriesProvider->getChildren($category) as $childCategory) {
57+
$mergeDataProvider = clone $this->mergeDataProviderPrototype;
58+
foreach ($this->childrenCategoriesProvider->getChildren($category, true) as $childCategory) {
4259
$childCategory->setStoreId($storeId);
4360
$childCategory->setData('save_rewrites_history', $category->getData('save_rewrites_history'));
44-
$urls = array_merge(
45-
$urls,
46-
$this->categoryUrlRewriteGeneratorFactory->create()->generate($childCategory)
61+
/** @var CategoryUrlRewriteGenerator $categoryUrlRewriteGenerator */
62+
$categoryUrlRewriteGenerator = $this->categoryUrlRewriteGeneratorFactory->create();
63+
$mergeDataProvider->merge(
64+
$categoryUrlRewriteGenerator->generate($childCategory, false, $rootCategoryId)
4765
);
4866
}
49-
return $urls;
67+
return $mergeDataProvider->getData();
5068
}
5169
}

0 commit comments

Comments
 (0)