Skip to content

Commit a09d71a

Browse files
fix Rest-API updating product stock_item deletes downloadable product data
1 parent 94f8ea3 commit a09d71a

File tree

5 files changed

+227
-114
lines changed

5 files changed

+227
-114
lines changed

app/code/Magento/Downloadable/Model/Link/UpdateHandler.php

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,18 @@
55
*/
66
namespace Magento\Downloadable\Model\Link;
77

8+
use Magento\Catalog\Api\Data\ProductInterface;
89
use Magento\Downloadable\Api\LinkRepositoryInterface as LinkRepository;
910
use Magento\Downloadable\Model\Product\Type;
1011
use Magento\Framework\EntityManager\Operation\ExtensionInterface;
1112

1213
/**
13-
* Class UpdateHandler
14+
* UpdateHandler for downloadable product links
1415
*/
1516
class UpdateHandler implements ExtensionInterface
1617
{
18+
private const GLOBAL_SCOPE_ID = 0;
19+
1720
/**
1821
* @var LinkRepository
1922
*/
@@ -28,35 +31,48 @@ public function __construct(LinkRepository $linkRepository)
2831
}
2932

3033
/**
34+
* Update links for downloadable product if exist
35+
*
3136
* @param object $entity
3237
* @param array $arguments
33-
* @return \Magento\Catalog\Api\Data\ProductInterface|object
34-
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
38+
* @return ProductInterface|object
3539
*/
3640
public function execute($entity, $arguments = [])
3741
{
38-
/** @var $entity \Magento\Catalog\Api\Data\ProductInterface */
39-
if ($entity->getTypeId() != Type::TYPE_DOWNLOADABLE) {
40-
return $entity;
42+
$links = $entity->getExtensionAttributes()->getDownloadableProductLinks();
43+
44+
/** @var $entity ProductInterface */
45+
if ($links && $entity->getTypeId() === Type::TYPE_DOWNLOADABLE) {
46+
$this->updateLinks($entity, $links);
4147
}
4248

43-
/** @var \Magento\Downloadable\Api\Data\LinkInterface[] $links */
44-
$links = $entity->getExtensionAttributes()->getDownloadableProductLinks() ?: [];
45-
$updatedLinks = [];
49+
return $entity;
50+
}
51+
52+
/**
53+
* Update product links
54+
*
55+
* @param ProductInterface $entity
56+
* @param array $links
57+
* @return void
58+
*/
59+
private function updateLinks(ProductInterface $entity, array $links): void
60+
{
61+
$isGlobalScope = (int) $entity->getStoreId() === self::GLOBAL_SCOPE_ID;
4662
$oldLinks = $this->linkRepository->getList($entity->getSku());
63+
64+
$updatedLinks = [];
4765
foreach ($links as $link) {
4866
if ($link->getId()) {
4967
$updatedLinks[$link->getId()] = true;
5068
}
51-
$this->linkRepository->save($entity->getSku(), $link, !(bool)$entity->getStoreId());
69+
$this->linkRepository->save($entity->getSku(), $link, $isGlobalScope);
5270
}
53-
/** @var \Magento\Catalog\Api\Data\ProductInterface $entity */
71+
5472
foreach ($oldLinks as $link) {
5573
if (!isset($updatedLinks[$link->getId()])) {
5674
$this->linkRepository->delete($link->getId());
5775
}
5876
}
59-
60-
return $entity;
6177
}
6278
}

app/code/Magento/Downloadable/Model/Sample/UpdateHandler.php

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,18 @@
55
*/
66
namespace Magento\Downloadable\Model\Sample;
77

8+
use Magento\Catalog\Api\Data\ProductInterface;
89
use Magento\Downloadable\Api\SampleRepositoryInterface as SampleRepository;
910
use Magento\Downloadable\Model\Product\Type;
1011
use Magento\Framework\EntityManager\Operation\ExtensionInterface;
1112

1213
/**
13-
* Class UpdateHandler
14+
* UpdateHandler for downloadable product samples
1415
*/
1516
class UpdateHandler implements ExtensionInterface
1617
{
18+
private const GLOBAL_SCOPE_ID = 0;
19+
1720
/**
1821
* @var SampleRepository
1922
*/
@@ -28,35 +31,48 @@ public function __construct(SampleRepository $sampleRepository)
2831
}
2932

3033
/**
34+
* Update samples for downloadable product if exist
35+
*
3136
* @param object $entity
3237
* @param array $arguments
33-
* @return \Magento\Catalog\Api\Data\ProductInterface|object
34-
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
38+
* @return ProductInterface|object
3539
*/
3640
public function execute($entity, $arguments = [])
3741
{
38-
/** @var $entity \Magento\Catalog\Api\Data\ProductInterface */
39-
if ($entity->getTypeId() != Type::TYPE_DOWNLOADABLE) {
40-
return $entity;
42+
$samples = $entity->getExtensionAttributes()->getDownloadableProductSamples();
43+
44+
/** @var $entity ProductInterface */
45+
if ($samples && $entity->getTypeId() === Type::TYPE_DOWNLOADABLE) {
46+
$this->updateSamples($entity, $samples);
4147
}
4248

43-
/** @var \Magento\Downloadable\Api\Data\SampleInterface[] $samples */
44-
$samples = $entity->getExtensionAttributes()->getDownloadableProductSamples() ?: [];
45-
$updatedSamples = [];
49+
return $entity;
50+
}
51+
52+
/**
53+
* Update product samples
54+
*
55+
* @param ProductInterface $entity
56+
* @param array $samples
57+
* @return void
58+
*/
59+
private function updateSamples(ProductInterface $entity, array $samples): void
60+
{
61+
$isGlobalScope = (int) $entity->getStoreId() === self::GLOBAL_SCOPE_ID;
4662
$oldSamples = $this->sampleRepository->getList($entity->getSku());
63+
64+
$updatedSamples = [];
4765
foreach ($samples as $sample) {
4866
if ($sample->getId()) {
4967
$updatedSamples[$sample->getId()] = true;
5068
}
51-
$this->sampleRepository->save($entity->getSku(), $sample, !(bool)$entity->getStoreId());
69+
$this->sampleRepository->save($entity->getSku(), $sample, $isGlobalScope);
5270
}
53-
/** @var \Magento\Catalog\Api\Data\ProductInterface $entity */
71+
5472
foreach ($oldSamples as $sample) {
5573
if (!isset($updatedSamples[$sample->getId()])) {
5674
$this->sampleRepository->delete($sample->getId());
5775
}
5876
}
59-
60-
return $entity;
6177
}
6278
}

app/code/Magento/Downloadable/Test/Unit/Model/Link/UpdateHandlerTest.php

Lines changed: 70 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
* Copyright © Magento, Inc. All rights reserved.
44
* See COPYING.txt for license details.
55
*/
6+
67
declare(strict_types=1);
78

89
namespace Magento\Downloadable\Test\Unit\Model\Link;
@@ -16,37 +17,72 @@
1617
use PHPUnit\Framework\MockObject\MockObject;
1718
use PHPUnit\Framework\TestCase;
1819

20+
/**
21+
* Test for \Magento\Downloadable\Model\Link\UpdateHandler.
22+
*/
1923
class UpdateHandlerTest extends TestCase
2024
{
21-
/** @var UpdateHandler */
22-
protected $model;
23-
24-
/** @var LinkRepositoryInterface|MockObject */
25-
protected $linkRepositoryMock;
26-
25+
/**
26+
* @var UpdateHandler
27+
*/
28+
private $model;
29+
30+
/**
31+
* @var LinkRepositoryInterface|MockObject
32+
*/
33+
private $linkRepositoryMock;
34+
35+
/**
36+
* @var LinkInterface|MockObject
37+
*/
38+
private $linkMock;
39+
40+
/**
41+
* @var ProductExtensionInterface|MockObject
42+
*/
43+
private $productExtensionMock;
44+
45+
/**
46+
* @var ProductInterface|MockObject
47+
*/
48+
private $entityMock;
49+
50+
/**
51+
* @inheritdoc
52+
*/
2753
protected function setUp(): void
2854
{
2955
$this->linkRepositoryMock = $this->getMockBuilder(LinkRepositoryInterface::class)
3056
->getMockForAbstractClass();
57+
$this->linkMock = $this->getMockBuilder(LinkInterface::class)
58+
->getMock();
59+
$this->productExtensionMock = $this->createMock(ProductExtensionInterface::class);
60+
$this->productExtensionMock->expects($this->once())
61+
->method('getDownloadableProductLinks')
62+
->willReturn([$this->linkMock]);
63+
$this->entityMock = $this->getMockBuilder(ProductInterface::class)
64+
->addMethods(['getStoreId'])
65+
->getMockForAbstractClass();
3166

3267
$this->model = new UpdateHandler(
3368
$this->linkRepositoryMock
3469
);
3570
}
3671

37-
public function testExecute()
72+
/**
73+
* Update links for downloadable product
74+
*
75+
* @return void
76+
*/
77+
public function testExecute(): void
3878
{
3979
$entitySku = 'sku';
4080
$entityStoreId = 0;
41-
$linkId = 11;
4281
$linkToDeleteId = 22;
4382

44-
/** @var LinkInterface|MockObject $linkMock */
45-
$linkMock = $this->getMockBuilder(LinkInterface::class)
46-
->getMock();
47-
$linkMock->expects($this->exactly(3))
83+
$this->linkMock->expects($this->exactly(3))
4884
->method('getId')
49-
->willReturn($linkId);
85+
->willReturn(1);
5086

5187
/** @var LinkInterface|MockObject $linkToDeleteMock */
5288
$linkToDeleteMock = $this->getMockBuilder(LinkInterface::class)
@@ -55,59 +91,49 @@ public function testExecute()
5591
->method('getId')
5692
->willReturn($linkToDeleteId);
5793

58-
/** @var ProductExtensionInterface|MockObject $productExtensionMock */
59-
$productExtensionMock = $this->getMockBuilder(ProductExtensionInterface::class)
60-
->setMethods(['getDownloadableProductLinks'])
61-
->getMockForAbstractClass();
62-
$productExtensionMock->expects($this->once())
63-
->method('getDownloadableProductLinks')
64-
->willReturn([$linkMock]);
65-
66-
/** @var ProductInterface|MockObject $entityMock */
67-
$entityMock = $this->getMockBuilder(ProductInterface::class)
68-
->setMethods(['getTypeId', 'getExtensionAttributes', 'getSku', 'getStoreId'])
69-
->getMockForAbstractClass();
70-
$entityMock->expects($this->once())
94+
$this->entityMock->expects($this->once())
7195
->method('getTypeId')
7296
->willReturn(Type::TYPE_DOWNLOADABLE);
73-
$entityMock->expects($this->once())
97+
$this->entityMock->expects($this->once())
7498
->method('getExtensionAttributes')
75-
->willReturn($productExtensionMock);
76-
$entityMock->expects($this->exactly(2))
99+
->willReturn($this->productExtensionMock);
100+
$this->entityMock->expects($this->exactly(2))
77101
->method('getSku')
78102
->willReturn($entitySku);
79-
$entityMock->expects($this->once())
103+
$this->entityMock->expects($this->once())
80104
->method('getStoreId')
81105
->willReturn($entityStoreId);
82106

83107
$this->linkRepositoryMock->expects($this->once())
84108
->method('getList')
85109
->with($entitySku)
86-
->willReturn([$linkMock, $linkToDeleteMock]);
110+
->willReturn([$this->linkMock, $linkToDeleteMock]);
87111
$this->linkRepositoryMock->expects($this->once())
88112
->method('save')
89-
->with($entitySku, $linkMock, !$entityStoreId);
113+
->with($entitySku, $this->linkMock, !$entityStoreId);
90114
$this->linkRepositoryMock->expects($this->once())
91115
->method('delete')
92116
->with($linkToDeleteId);
93117

94-
$this->assertEquals($entityMock, $this->model->execute($entityMock));
118+
$this->assertEquals($this->entityMock, $this->model->execute($this->entityMock));
95119
}
96120

97-
public function testExecuteNonDownloadable()
121+
/**
122+
* Update links for non downloadable product
123+
*
124+
* @return void
125+
*/
126+
public function testExecuteNonDownloadable(): void
98127
{
99-
/** @var ProductInterface|MockObject $entityMock */
100-
$entityMock = $this->getMockBuilder(ProductInterface::class)
101-
->setMethods(['getTypeId', 'getExtensionAttributes', 'getSku', 'getStoreId'])
102-
->getMockForAbstractClass();
103-
$entityMock->expects($this->once())
128+
$this->entityMock->expects($this->once())
104129
->method('getTypeId')
105130
->willReturn(Type::TYPE_DOWNLOADABLE . 'some');
106-
$entityMock->expects($this->never())
107-
->method('getExtensionAttributes');
108-
$entityMock->expects($this->never())
131+
$this->entityMock->expects($this->once())
132+
->method('getExtensionAttributes')
133+
->willReturn($this->productExtensionMock);
134+
$this->entityMock->expects($this->never())
109135
->method('getSku');
110-
$entityMock->expects($this->never())
136+
$this->entityMock->expects($this->never())
111137
->method('getStoreId');
112138

113139
$this->linkRepositoryMock->expects($this->never())
@@ -117,6 +143,6 @@ public function testExecuteNonDownloadable()
117143
$this->linkRepositoryMock->expects($this->never())
118144
->method('delete');
119145

120-
$this->assertEquals($entityMock, $this->model->execute($entityMock));
146+
$this->assertEquals($this->entityMock, $this->model->execute($this->entityMock));
121147
}
122148
}

0 commit comments

Comments
 (0)