Skip to content

Commit 76987a9

Browse files
committed
Merge branch '2.3-develop' into MC-30066
2 parents 9edfb31 + 5206031 commit 76987a9

File tree

19 files changed

+768
-207
lines changed

19 files changed

+768
-207
lines changed

app/code/Magento/DownloadableImportExport/Helper/Data.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
use Magento\DownloadableImportExport\Model\Import\Product\Type\Downloadable;
99

1010
/**
11-
* Class Data
11+
* Helper for import-export downloadable product
1212
*/
1313
class Data extends \Magento\Framework\App\Helper\AbstractHelper
1414
{
@@ -47,6 +47,7 @@ public function isRowDownloadableNoValid(array $rowData)
4747
* @param array $option
4848
* @param array $existingOptions
4949
* @return array
50+
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
5051
*/
5152
public function fillExistOptions(array $base, array $option, array $existingOptions)
5253
{
@@ -59,6 +60,9 @@ public function fillExistOptions(array $base, array $option, array $existingOpti
5960
&& $option['sample_file'] == $existingOption['sample_file']
6061
&& $option['sample_type'] == $existingOption['sample_type']
6162
&& $option['product_id'] == $existingOption['product_id']) {
63+
if (empty($existingOption['website_id'])) {
64+
unset($existingOption['website_id']);
65+
}
6266
$result = array_replace($base, $option, $existingOption);
6367
}
6468
}

app/code/Magento/DownloadableImportExport/Helper/Uploader.php

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
use Magento\Framework\App\Filesystem\DirectoryList;
99

1010
/**
11-
* Class Uploader
11+
* Uploader helper for downloadable products
1212
*/
1313
class Uploader extends \Magento\Framework\App\Helper\AbstractHelper
1414
{
@@ -105,6 +105,17 @@ public function getUploader($type, $parameters)
105105
return $this->fileUploader;
106106
}
107107

108+
/**
109+
* Check a file or directory exists
110+
*
111+
* @param string $fileName
112+
* @return bool
113+
*/
114+
public function isFileExist(string $fileName): bool
115+
{
116+
return $this->mediaDirectory->isExist($this->fileUploader->getDestDir().$fileName);
117+
}
118+
108119
/**
109120
* Get all allowed extensions
110121
*
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
namespace Magento\DownloadableImportExport\Model\Export\Product\Type;
7+
8+
use Magento\CatalogImportExport\Model\Export\Product\Type\AbstractType;
9+
10+
/**
11+
* Class Downloadable for composite CatalogImportExport
12+
*/
13+
class Downloadable extends AbstractType
14+
{
15+
}
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
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\DownloadableImportExport\Model\Export;
9+
10+
use Magento\Downloadable\Model\LinkRepository;
11+
use Magento\Downloadable\Model\SampleRepository;
12+
use Magento\Catalog\Model\ResourceModel\Product\Collection as ProductCollection;
13+
use Magento\CatalogImportExport\Model\Export\RowCustomizerInterface;
14+
use Magento\CatalogImportExport\Model\Import\Product as ImportProduct;
15+
use Magento\Downloadable\Model\Product\Type as Type;
16+
use Magento\ImportExport\Model\Import;
17+
use Magento\Store\Model\Store;
18+
use Magento\Store\Model\StoreManagerInterface;
19+
use Magento\DownloadableImportExport\Model\Import\Product\Type\Downloadable;
20+
21+
/**
22+
* Customizes output during export
23+
*/
24+
class RowCustomizer implements RowCustomizerInterface
25+
{
26+
/**
27+
* @var array
28+
*/
29+
private $downloadableData = [];
30+
31+
/**
32+
* @var string[]
33+
*/
34+
private $downloadableColumns = [
35+
Downloadable::COL_DOWNLOADABLE_LINKS,
36+
Downloadable::COL_DOWNLOADABLE_SAMPLES,
37+
];
38+
39+
/**
40+
* @var LinkRepository
41+
*/
42+
private $linkRepository;
43+
44+
/**
45+
* @var SampleRepository
46+
*/
47+
private $sampleRepository;
48+
49+
/**
50+
* @var StoreManagerInterface
51+
*/
52+
private $storeManager;
53+
54+
/**
55+
* @param StoreManagerInterface $storeManager
56+
* @param LinkRepository $linkRepository
57+
* @param SampleRepository $sampleRepository
58+
*/
59+
public function __construct(
60+
StoreManagerInterface $storeManager,
61+
LinkRepository $linkRepository,
62+
SampleRepository $sampleRepository
63+
) {
64+
$this->storeManager = $storeManager;
65+
$this->linkRepository = $linkRepository;
66+
$this->sampleRepository = $sampleRepository;
67+
}
68+
69+
/**
70+
* Prepare configurable data for export
71+
*
72+
* @param ProductCollection $collection
73+
* @param int[] $productIds
74+
* @return void
75+
*/
76+
public function prepareData($collection, $productIds): void
77+
{
78+
$productCollection = clone $collection;
79+
$productCollection->addAttributeToFilter('entity_id', ['in' => $productIds])
80+
->addAttributeToFilter('type_id', ['eq' => Type::TYPE_DOWNLOADABLE])
81+
->addAttributeToSelect('links_title')
82+
->addAttributeToSelect('samples_title');
83+
// set global scope during export
84+
$this->storeManager->setCurrentStore(Store::DEFAULT_STORE_ID);
85+
foreach ($collection as $product) {
86+
$productLinks = $this->linkRepository->getLinksByProduct($product);
87+
$productSamples = $this->sampleRepository->getSamplesByProduct($product);
88+
$this->downloadableData[$product->getId()] = [];
89+
$linksData = [];
90+
$samplesData = [];
91+
foreach ($productLinks as $linkId => $link) {
92+
$linkData = $link->getData();
93+
$linkData['group_title'] = $product->getData('links_title');
94+
$linksData[$linkId] = $this->optionRowToCellString($linkData);
95+
}
96+
foreach ($productSamples as $sampleId => $sample) {
97+
$sampleData = $sample->getData();
98+
$sampleData['group_title'] = $product->getData('samples_title');
99+
$samplesData[$sampleId] = $this->optionRowToCellString($sampleData);
100+
}
101+
$this->downloadableData[$product->getId()] = [
102+
Downloadable::COL_DOWNLOADABLE_LINKS => implode(
103+
ImportProduct::PSEUDO_MULTI_LINE_SEPARATOR,
104+
$linksData
105+
),
106+
Downloadable::COL_DOWNLOADABLE_SAMPLES => implode(
107+
Import::DEFAULT_GLOBAL_MULTI_VALUE_SEPARATOR,
108+
$samplesData
109+
)];
110+
}
111+
}
112+
113+
/**
114+
* Convert option row to cell string
115+
*
116+
* @param array $option
117+
* @return string
118+
*/
119+
private function optionRowToCellString(array $option): string
120+
{
121+
$result = [];
122+
foreach ($option as $attributeCode => $value) {
123+
if ($value) {
124+
$result[] = $attributeCode . ImportProduct::PAIR_NAME_VALUE_SEPARATOR . $value;
125+
}
126+
}
127+
return implode(Import::DEFAULT_GLOBAL_MULTI_VALUE_SEPARATOR, $result);
128+
}
129+
130+
/**
131+
* Set headers columns
132+
*
133+
* @param array $columns
134+
* @return array
135+
*/
136+
public function addHeaderColumns($columns): array
137+
{
138+
return array_merge($columns, $this->downloadableColumns);
139+
}
140+
141+
/**
142+
* Add downloadable data for export
143+
*
144+
* @param array $dataRow
145+
* @param int $productId
146+
* @return array
147+
*/
148+
public function addData($dataRow, $productId): array
149+
{
150+
if (!empty($this->downloadableData[$productId])) {
151+
$dataRow = array_merge($dataRow, $this->downloadableData[$productId]);
152+
}
153+
return $dataRow;
154+
}
155+
156+
/**
157+
* Calculate the largest links block
158+
*
159+
* @param array $additionalRowsCount
160+
* @param int $productId
161+
* @return array
162+
*/
163+
public function getAdditionalRowsCount($additionalRowsCount, $productId): array
164+
{
165+
if (!empty($this->downloadableData[$productId])) {
166+
$additionalRowsCount = max($additionalRowsCount, count($this->downloadableData[$productId]));
167+
}
168+
return $additionalRowsCount;
169+
}
170+
}

app/code/Magento/DownloadableImportExport/Model/Import/Product/Type/Downloadable.php

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -896,12 +896,16 @@ protected function parseSampleOption($values)
896896
protected function uploadDownloadableFiles($fileName, $type = 'links', $renameFileOff = false)
897897
{
898898
try {
899-
$res = $this->uploaderHelper->getUploader($type, $this->parameters)->move($fileName, $renameFileOff);
900-
return $res['file'];
899+
$uploader = $this->uploaderHelper->getUploader($type, $this->parameters);
900+
if (!$this->uploaderHelper->isFileExist($fileName)) {
901+
$uploader->move($fileName, $renameFileOff);
902+
$fileName = $uploader['file'];
903+
}
901904
} catch (\Exception $e) {
902905
$this->_entityModel->addRowError(self::ERROR_MOVE_FILE, $this->rowNum);
903-
return '';
906+
$fileName = '';
904907
}
908+
return $fileName;
905909
}
906910

907911
/**

app/code/Magento/DownloadableImportExport/Test/Unit/Model/Import/Product/Type/DownloadableTest.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManager;
1010

1111
/**
12-
* Class DownloadableTest
12+
* Class DownloadableTest for downloadable products import
1313
*
1414
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
1515
*/
@@ -164,7 +164,7 @@ protected function setUp()
164164
// 7. $fileHelper
165165
$this->uploaderHelper = $this->createPartialMock(
166166
\Magento\DownloadableImportExport\Helper\Uploader::class,
167-
['getUploader']
167+
['getUploader', 'isFileExist']
168168
);
169169
$this->uploaderHelper->expects($this->any())->method('getUploader')->willReturn($this->uploaderMock);
170170
$this->downloadableHelper = $this->createPartialMock(
@@ -660,6 +660,7 @@ public function testSetUploaderDirFalse($newSku, $bunch, $allowImport, $parsedOp
660660
$metadataPoolMock->expects($this->any())->method('getLinkField')->willReturn('entity_id');
661661
$this->downloadableHelper->expects($this->atLeastOnce())
662662
->method('fillExistOptions')->willReturn($parsedOptions['link']);
663+
$this->uploaderHelper->method('isFileExist')->willReturn(false);
663664

664665
$this->downloadableModelMock = $this->objectManagerHelper->getObject(
665666
\Magento\DownloadableImportExport\Model\Import\Product\Type\Downloadable::class,
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?xml version="1.0"?>
2+
<!--
3+
/**
4+
* Copyright © Magento, Inc. All rights reserved.
5+
* See COPYING.txt for license details.
6+
*/
7+
-->
8+
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
9+
<type name="Magento\CatalogImportExport\Model\Export\RowCustomizer\Composite">
10+
<arguments>
11+
<argument name="customizers" xsi:type="array">
12+
<item name="downloadableProduct" xsi:type="string">Magento\DownloadableImportExport\Model\Export\RowCustomizer</item>
13+
</argument>
14+
</arguments>
15+
</type>
16+
</config>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?xml version="1.0"?>
2+
<!--
3+
/**
4+
* Copyright © Magento, Inc. All rights reserved.
5+
* See COPYING.txt for license details.
6+
*/
7+
-->
8+
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_ImportExport:etc/export.xsd">
9+
<entityType entity="catalog_product" name="downloadable" model="Magento\DownloadableImportExport\Model\Export\Product\Type\Downloadable" />
10+
</config>

app/code/Magento/ImportExport/Ui/Component/Columns/ExportGridActions.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,17 @@ public function prepareDataSource(array $dataSource)
5656
$name = $this->getData('name');
5757
if (isset($item['file_name'])) {
5858
$item[$name]['view'] = [
59-
'href' => $this->urlBuilder->getUrl(Download::URL, ['filename' => $item['file_name']]),
59+
'href' => $this->urlBuilder->getUrl(
60+
Download::URL,
61+
['_query' => ['filename' => $item['file_name']]]
62+
),
6063
'label' => __('Download')
6164
];
6265
$item[$name]['delete'] = [
63-
'href' => $this->urlBuilder->getUrl(Delete::URL, ['filename' => $item['file_name']]),
66+
'href' => $this->urlBuilder->getUrl(
67+
Delete::URL,
68+
['_query' => ['filename' => $item['file_name']]]
69+
),
6470
'label' => __('Delete'),
6571
'confirm' => [
6672
'title' => __('Delete'),

app/code/Magento/ImportExport/Ui/DataProvider/ExportFileDataProvider.php

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ public function getData()
100100
}
101101
$result = [];
102102
foreach ($files as $file) {
103-
$result['items'][]['file_name'] = $this->fileIO->getPathInfo($file)['basename'];
103+
$result['items'][]['file_name'] = $this->getPathToExportFile($this->fileIO->getPathInfo($file));
104104
}
105105

106106
$pageSize = (int) $this->request->getParam('paging')['pageSize'];
@@ -112,6 +112,31 @@ public function getData()
112112
return $result;
113113
}
114114

115+
/**
116+
* Return relative export file path after "var/export"
117+
*
118+
* @param mixed $file
119+
* @return string
120+
*/
121+
private function getPathToExportFile($file): string
122+
{
123+
$directory = $this->fileSystem->getDirectoryRead(DirectoryList::VAR_DIR);
124+
$delimiter = '/';
125+
$cutPath = explode(
126+
$delimiter,
127+
$directory->getAbsolutePath() . 'export'
128+
);
129+
$filePath = explode(
130+
$delimiter,
131+
$file['dirname']
132+
);
133+
134+
return ltrim(
135+
implode($delimiter, array_diff($filePath, $cutPath)) . $delimiter . $file['basename'],
136+
$delimiter
137+
);
138+
}
139+
115140
/**
116141
* Get files from directory path, sort them by date modified and return sorted array of full path to files
117142
*
@@ -127,8 +152,10 @@ private function getExportFiles(string $directoryPath): array
127152
return [];
128153
}
129154
foreach ($files as $filePath) {
130-
//phpcs:ignore Magento2.Functions.DiscouragedFunction
131-
$sortedFiles[filemtime($filePath)] = $filePath;
155+
if ($this->file->isFile($filePath)) {
156+
//phpcs:ignore Magento2.Functions.DiscouragedFunction
157+
$sortedFiles[filemtime($filePath)] = $filePath;
158+
}
132159
}
133160
//sort array elements using key value
134161
krsort($sortedFiles);

0 commit comments

Comments
 (0)