1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Store\Model\Config;
use Magento\Framework\App\CacheInterface;
use Magento\Framework\App\DeploymentConfig\ImporterInterface;
use Magento\Framework\Exception\State\InvalidTransitionException;
use Magento\Store\Model\Config\Importer\DataDifferenceCalculator;
use Magento\Store\Model\Config\Importer\Processor\ProcessorFactory;
use Magento\Store\Model\ScopeInterface;
use Magento\Store\Model\StoreManagerInterface;
use Magento\Store\Model\ResourceModel\Website;
/**
* Imports stores, websites and groups from transmitted data.
*/
class Importer implements ImporterInterface
{
/**
* The data difference calculator.
*
* @var DataDifferenceCalculator
*/
private $dataDifferenceCalculator;
/**
* The factory for processors.
*
* @var ProcessorFactory
*/
private $processFactory;
/**
* The manager for operations with store.
*
* @var StoreManagerInterface
*/
private $storeManager;
/**
* The resource of transaction.
*
* @var Website
*/
private $resource;
/**
* The application cache manager.
*
* @var CacheInterface
*/
private $cacheManager;
/**
* @param DataDifferenceCalculator $dataDifferenceCalculator The factory for data difference calculators
* @param ProcessorFactory $processFactory The factory for processes
* @param StoreManagerInterface $storeManager The manager for operations with store
* @param CacheInterface $cacheManager The application cache manager
* @param Website $resource The resource of transaction
*/
public function __construct(
DataDifferenceCalculator $dataDifferenceCalculator,
ProcessorFactory $processFactory,
StoreManagerInterface $storeManager,
CacheInterface $cacheManager,
Website $resource
) {
$this->dataDifferenceCalculator = $dataDifferenceCalculator;
$this->processFactory = $processFactory;
$this->storeManager = $storeManager;
$this->cacheManager = $cacheManager;
$this->resource = $resource;
}
/**
* Imports the store data into the application.
* After the import it flushes the store caches.
*
* {@inheritdoc}
*/
public function import(array $data)
{
$actions = [
ProcessorFactory::TYPE_CREATE,
ProcessorFactory::TYPE_DELETE,
ProcessorFactory::TYPE_UPDATE
];
$messages = ['Stores were processed'];
try {
$newGroups = $this->getGroupsToCreate($data);
if ($newGroups) {
$messages[] = sprintf(
$this->getStoreGroupAssignMessage(),
implode(', ', array_column($newGroups, 'name'))
);
}
// during import websites/stores database already has new entities
// but cache is outdated which can cause to error in some cases
$this->reinitStores();
$this->resource->beginTransaction();
foreach ($actions as $action) {
$this->processFactory->create($action)->run($data);
}
} catch (\Exception $exception) {
$this->resource->rollBack();
$this->reinitStores();
throw new InvalidTransitionException(__('%1', $exception->getMessage()), $exception);
}
$this->resource->commit();
$this->reinitStores();
return $messages;
}
/**
* Reinitialize store list.
*
* @return void
*/
private function reinitStores()
{
$this->storeManager->reinitStores();
$this->cacheManager->clean();
}
/**
* Retrieves message reminder about root category assigning.
*
* @return string
*/
private function getStoreGroupAssignMessage()
{
return 'The following new store groups must be associated with a root category: %s. '
. PHP_EOL
. 'Associate a store group with a root category in the Admin Panel: Stores > Settings > All Stores.';
}
/**
* Checks which new store groups will be created.
*
* @param array $data The data set.
* @return array
*/
private function getGroupsToCreate(array $data)
{
if (!isset($data[ScopeInterface::SCOPE_GROUPS])) {
return [];
}
$groups = $this->dataDifferenceCalculator->getItemsToCreate(
ScopeInterface::SCOPE_GROUPS,
$data[ScopeInterface::SCOPE_GROUPS]
);
return $groups;
}
/**
* Retrieves all affected entities during the import procedure.
*
* {@inheritdoc}
*/
public function getWarningMessages(array $data)
{
$messages = [];
foreach ($data as $scope => $scopeData) {
$messageMap = [
'These %s will be deleted: %s' => $this->dataDifferenceCalculator->getItemsToDelete($scope, $scopeData),
'These %s will be updated: %s' => $this->dataDifferenceCalculator->getItemsToUpdate($scope, $scopeData),
'These %s will be created: %s' => $this->dataDifferenceCalculator->getItemsToCreate($scope, $scopeData),
];
foreach ($messageMap as $message => $items) {
if (!$items) {
continue;
}
$messages[] = $this->formatMessage($message, $items, $scope);
}
}
return $messages;
}
/**
* Formats message to appropriate format.
*
* @param string $message The message to display
* @param array $items The items to be used
* @param string $scope The given scope
* @return string
*/
private function formatMessage($message, array $items, $scope)
{
return sprintf(
$message,
ucfirst($scope),
implode(', ', array_column($items, 'name'))
);
}
}