Skip to content

Commit 5fc9a1c

Browse files
committed
Merge branch 'ACP2E-1508' of https://github.com/magento-l3/magento2ce into PR-06022023
2 parents 1112cab + 5e3202c commit 5fc9a1c

File tree

4 files changed

+255
-0
lines changed

4 files changed

+255
-0
lines changed
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Catalog\Model\System\Config\Backend\Rss;
9+
10+
use Magento\Catalog\Api\Data\ProductInterface;
11+
use Magento\Catalog\Api\ProductAttributeRepositoryInterface;
12+
use Magento\Framework\App\Cache\TypeListInterface;
13+
use Magento\Framework\App\Config\ScopeConfigInterface;
14+
use Magento\Framework\App\Config\Value as ConfigValue;
15+
use Magento\Framework\App\ObjectManager;
16+
use Magento\Framework\Data\Collection\AbstractDb;
17+
use Magento\Framework\Model\Context;
18+
use Magento\Framework\Model\ResourceModel\AbstractResource;
19+
use Magento\Framework\Registry;
20+
21+
class Category extends ConfigValue
22+
{
23+
/**
24+
* @var ProductAttributeRepositoryInterface
25+
*/
26+
private $productAttributeRepository;
27+
28+
/**
29+
* @param Context $context
30+
* @param Registry $registry
31+
* @param ScopeConfigInterface $config
32+
* @param TypeListInterface $cacheTypeList
33+
* @param AbstractResource|null $resource
34+
* @param AbstractDb|null $resourceCollection
35+
* @param array $data
36+
* @param ProductAttributeRepositoryInterface|null $productAttributeRepository
37+
*/
38+
public function __construct(
39+
Context $context,
40+
Registry $registry,
41+
ScopeConfigInterface $config,
42+
TypeListInterface $cacheTypeList,
43+
AbstractResource $resource = null,
44+
AbstractDb $resourceCollection = null,
45+
array $data = [],
46+
ProductAttributeRepositoryInterface $productAttributeRepository = null
47+
) {
48+
parent::__construct($context, $registry, $config, $cacheTypeList, $resource, $resourceCollection, $data);
49+
50+
$this->productAttributeRepository = $productAttributeRepository ??
51+
ObjectManager::getInstance()->get(ProductAttributeRepositoryInterface::class);
52+
}
53+
54+
/**
55+
* @inheritdoc
56+
*/
57+
public function afterSave()
58+
{
59+
if ($this->isValueChanged() && $this->getValue()) {
60+
$updatedAtAttr = $this->productAttributeRepository->get(ProductInterface::UPDATED_AT);
61+
if (!$updatedAtAttr->getUsedForSortBy()) {
62+
$updatedAtAttr->setUsedForSortBy(true);
63+
$this->productAttributeRepository->save($updatedAtAttr);
64+
}
65+
}
66+
67+
return parent::afterSave();
68+
}
69+
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Catalog\Test\Unit\Model\System\Config\Backend\Rss;
9+
10+
use Magento\Catalog\Api\Data\ProductAttributeInterface;
11+
use Magento\Catalog\Api\ProductAttributeRepositoryInterface;
12+
use Magento\Catalog\Model\System\Config\Backend\Rss\Category;
13+
use Magento\Framework\App\Cache\TypeListInterface;
14+
use Magento\Framework\App\Config\ScopeConfigInterface;
15+
use Magento\Framework\Data\Collection\AbstractDb;
16+
use Magento\Framework\Event\ManagerInterface as EventManager;
17+
use Magento\Framework\Model\Context;
18+
use Magento\Framework\Model\ResourceModel\AbstractResource;
19+
use Magento\Framework\Registry;
20+
use PHPUnit\Framework\MockObject\MockObject;
21+
use PHPUnit\Framework\TestCase;
22+
23+
class CategoryTest extends TestCase
24+
{
25+
/**
26+
* @var ScopeConfigInterface|MockObject
27+
*/
28+
private $configMock;
29+
30+
/**
31+
* @var ProductAttributeRepositoryInterface|MockObject
32+
*/
33+
private $productAttributeRepositoryMock;
34+
35+
/**
36+
* @var Category
37+
*/
38+
private $model;
39+
40+
protected function setUp(): void
41+
{
42+
$contextMock = $this->createMock(Context::class);
43+
$eventManagerMock = $this->createMock(EventManager::class);
44+
$contextMock->method('getEventDispatcher')
45+
->willReturn($eventManagerMock);
46+
$registryMock = $this->createMock(Registry::class);
47+
$this->configMock = $this->createMock(ScopeConfigInterface::class);
48+
$cacheTypeListMock = $this->createMock(TypeListInterface::class);
49+
$resourceMock = $this->createMock(AbstractResource::class);
50+
$resourceCollectionMock = $this->createMock(AbstractDb::class);
51+
$this->productAttributeRepositoryMock = $this->createMock(ProductAttributeRepositoryInterface::class);
52+
$this->model = new Category(
53+
$contextMock,
54+
$registryMock,
55+
$this->configMock,
56+
$cacheTypeListMock,
57+
$resourceMock,
58+
$resourceCollectionMock,
59+
['path' => 'rss/catalog/category'],
60+
$this->productAttributeRepositoryMock
61+
);
62+
}
63+
64+
/**
65+
* @dataProvider afterSaveDataProvider
66+
* @param string $oldValue
67+
* @param string $newValue
68+
* @param bool $isUsedForSort
69+
* @param bool $isUpdateNeeded
70+
*/
71+
public function testAfterSave(string $oldValue, string $newValue, bool $isUsedForSort, bool $isUpdateNeeded): void
72+
{
73+
$this->configMock->expects($this->atLeastOnce())
74+
->method('getValue')
75+
->with('rss/catalog/category', 'default', null)
76+
->willReturn($oldValue);
77+
78+
$productAttributeMock = $this->createMock(ProductAttributeInterface::class);
79+
$productAttributeMock->method('getUsedForSortBy')
80+
->willReturn($isUsedForSort);
81+
$this->productAttributeRepositoryMock->method('get')
82+
->with('updated_at')
83+
->willReturn($productAttributeMock);
84+
85+
$productAttributeMock->expects($this->exactly((int) $isUpdateNeeded))
86+
->method('setUsedForSortBy')
87+
->with(true)
88+
->willReturnSelf();
89+
$this->productAttributeRepositoryMock->expects($this->exactly((int) $isUpdateNeeded))
90+
->method('save')
91+
->with($productAttributeMock)
92+
->willReturn($productAttributeMock);
93+
94+
$this->model->setValue($newValue);
95+
$this->model->afterSave();
96+
}
97+
98+
public function afterSaveDataProvider(): array
99+
{
100+
return [
101+
['0', '1', false, true],
102+
['0', '0', false, false],
103+
['1', '0', false, false],
104+
['0', '1', true, false],
105+
];
106+
}
107+
}

app/code/Magento/Catalog/etc/adminhtml/system.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@
199199
<field id="category" translate="label" type="select" sortOrder="14" showInDefault="1" showInWebsite="1" showInStore="1">
200200
<label>Top Level Category</label>
201201
<source_model>Magento\Config\Model\Config\Source\Enabledisable</source_model>
202+
<backend_model>Magento\Catalog\Model\System\Config\Backend\Rss\Category</backend_model>
202203
</field>
203204
</group>
204205
</section>
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Catalog\Model\Rss;
9+
10+
use Magento\Catalog\Test\Fixture\Category as CategoryFixture;
11+
use Magento\Catalog\Test\Fixture\Product as ProductFixture;
12+
use Magento\Config\Model\Config as ConfigModel;
13+
use Magento\Framework\App\Area;
14+
use Magento\Framework\App\Config\ConfigResource\ConfigInterface as ConfigResource;
15+
use Magento\Framework\Indexer\IndexerRegistry;
16+
use Magento\Store\Model\StoreManagerInterface;
17+
use Magento\TestFramework\Fixture\AppArea;
18+
use Magento\TestFramework\Fixture\DataFixture;
19+
use Magento\TestFramework\Fixture\DataFixtureStorage;
20+
use Magento\TestFramework\Fixture\DataFixtureStorageManager;
21+
use Magento\TestFramework\Fixture\DbIsolation;
22+
use Magento\TestFramework\Helper\Bootstrap;
23+
use PHPUnit\Framework\TestCase;
24+
25+
#[
26+
AppArea(Area::AREA_ADMINHTML),
27+
DbIsolation(false),
28+
]
29+
class CategoryTest extends TestCase
30+
{
31+
/**
32+
* @var DataFixtureStorage
33+
*/
34+
private $fixtureStorage;
35+
36+
/**
37+
* @var Category
38+
*/
39+
private $model;
40+
41+
/**
42+
* @var StoreManagerInterface
43+
*/
44+
private $storeManager;
45+
46+
protected function setUp(): void
47+
{
48+
$configModel = Bootstrap::getObjectManager()->create(ConfigModel::class);
49+
$configModel->setDataByPath('rss/catalog/category', 1);
50+
$configModel->save();
51+
$indexerRegistry = Bootstrap::getObjectManager()->get(IndexerRegistry::class);
52+
$indexerRegistry->get('catalogsearch_fulltext')->reindexAll();
53+
54+
$this->fixtureStorage = DataFixtureStorageManager::getStorage();
55+
$this->model = Bootstrap::getObjectManager()->create(Category::class);
56+
$this->storeManager = Bootstrap::getObjectManager()->get(StoreManagerInterface::class);
57+
}
58+
59+
protected function tearDown(): void
60+
{
61+
$configResource = Bootstrap::getObjectManager()->get(ConfigResource::class);
62+
$configResource->deleteConfig('rss/catalog/category');
63+
}
64+
65+
#[
66+
DataFixture(CategoryFixture::class, as: 'c1'),
67+
DataFixture(ProductFixture::class, ['sku' => 'p1', 'category_ids' => ['$c1.id$']], 'p1'),
68+
]
69+
public function testGetProductCollection(): void
70+
{
71+
$category = $this->fixtureStorage->get('c1');
72+
$store = $this->storeManager->getStore('default');
73+
$productCollection = $this->model->getProductCollection($category, $store->getId());
74+
self::assertEquals(1, $productCollection->count());
75+
$product = $productCollection->getFirstItem();
76+
self::assertEquals('p1', $product->getSku());
77+
}
78+
}

0 commit comments

Comments
 (0)