|
1
|
|
|
<?php |
|
2
|
|
|
/** |
|
3
|
|
|
* (c) shopware AG <[email protected]> |
|
4
|
|
|
* For the full copyright and license information, please view the LICENSE |
|
5
|
|
|
* file that was distributed with this source code. |
|
6
|
|
|
*/ |
|
7
|
|
|
|
|
8
|
|
|
namespace ShopwarePlugins\Connect\Bootstrap; |
|
9
|
|
|
|
|
10
|
|
|
use Shopware\CustomModels\Connect\Attribute; |
|
11
|
|
|
use Shopware\Components\Model\ModelManager; |
|
12
|
|
|
use Enlight_Components_Db_Adapter_Pdo_Mysql as Pdo; |
|
13
|
|
|
use Shopware\Models\Attribute\Configuration; |
|
14
|
|
|
use Shopware\Models\Order\Status; |
|
15
|
|
|
use ShopwarePlugins\Connect\Components\ProductQuery\BaseProductQuery; |
|
16
|
|
|
use ShopwarePlugins\Connect\Components\Utils\ConnectOrderUtil; |
|
17
|
|
|
|
|
18
|
|
|
/** |
|
19
|
|
|
* Updates existing versions of the plugin |
|
20
|
|
|
* |
|
21
|
|
|
* Class Update |
|
22
|
|
|
* @package ShopwarePlugins\Connect\Bootstrap |
|
23
|
|
|
*/ |
|
24
|
|
|
class Update |
|
25
|
|
|
{ |
|
26
|
|
|
/** |
|
27
|
|
|
* @var \Shopware_Plugins_Backend_SwagConnect_Bootstrap |
|
28
|
|
|
*/ |
|
29
|
|
|
protected $bootstrap; |
|
30
|
|
|
|
|
31
|
|
|
/** |
|
32
|
|
|
* @var Pdo |
|
33
|
|
|
*/ |
|
34
|
|
|
protected $db; |
|
35
|
|
|
|
|
36
|
|
|
/** |
|
37
|
|
|
* @var ModelManager |
|
38
|
|
|
*/ |
|
39
|
|
|
protected $modelManager; |
|
40
|
|
|
|
|
41
|
|
|
/** |
|
42
|
|
|
* @var string |
|
43
|
|
|
*/ |
|
44
|
|
|
protected $version; |
|
45
|
|
|
|
|
46
|
|
|
/** |
|
47
|
|
|
* Setup constructor. |
|
48
|
|
|
* @param \Shopware_Plugins_Backend_SwagConnect_Bootstrap $bootstrap |
|
49
|
|
|
* @param ModelManager $modelManager |
|
50
|
|
|
* @param Pdo $db |
|
51
|
|
|
* @param $version |
|
52
|
|
|
*/ |
|
53
|
|
View Code Duplication |
public function __construct( |
|
|
|
|
|
|
54
|
|
|
\Shopware_Plugins_Backend_SwagConnect_Bootstrap $bootstrap, |
|
55
|
|
|
ModelManager $modelManager, |
|
56
|
|
|
Pdo $db, |
|
57
|
|
|
$version |
|
58
|
|
|
) { |
|
59
|
|
|
$this->bootstrap = $bootstrap; |
|
60
|
|
|
$this->modelManager = $modelManager; |
|
61
|
|
|
$this->db = $db; |
|
62
|
|
|
$this->version = $version; |
|
63
|
|
|
} |
|
64
|
|
|
|
|
65
|
|
|
public function run() |
|
66
|
|
|
{ |
|
67
|
|
|
// Force an SDK re-verify |
|
68
|
|
|
$this->reVerifySDK(); |
|
69
|
|
|
|
|
70
|
|
|
$this->createExportedFlag(); |
|
71
|
|
|
$this->removeRedirectMenu(); |
|
72
|
|
|
$this->updateConnectAttribute(); |
|
73
|
|
|
$this->addConnectDescriptionElement(); |
|
74
|
|
|
$this->updateProductDescriptionSetting(); |
|
75
|
|
|
$this->createUpdateAdditionalDescriptionColumn(); |
|
76
|
|
|
$this->createDynamicStreamTable(); |
|
77
|
|
|
$this->addOrderStatus(); |
|
78
|
|
|
$this->fixExportDescriptionSettings(); |
|
79
|
|
|
$this->fixMarketplaceUrl(); |
|
80
|
|
|
$this->addIndexToChangeTable(); |
|
81
|
|
|
$this->removeDuplicatedMenuItems(); |
|
82
|
|
|
$this->addConnectItemsIndex(); |
|
83
|
|
|
|
|
84
|
|
|
return true; |
|
85
|
|
|
} |
|
86
|
|
|
|
|
87
|
|
|
/** |
|
88
|
|
|
* Forces the SDK to re-verify the API key |
|
89
|
|
|
*/ |
|
90
|
|
|
public function reVerifySDK() |
|
91
|
|
|
{ |
|
92
|
|
|
$this->db->query(' |
|
93
|
|
|
UPDATE sw_connect_shop_config |
|
94
|
|
|
SET s_config = ? |
|
95
|
|
|
WHERE s_shop = "_last_update_" |
|
96
|
|
|
LIMIT 1; ', |
|
97
|
|
|
[time() - 8 * 60 * 60 * 24] |
|
98
|
|
|
); |
|
99
|
|
|
} |
|
100
|
|
|
|
|
101
|
|
|
private function createExportedFlag() |
|
102
|
|
|
{ |
|
103
|
|
|
if (version_compare($this->version, '1.0.1', '<=')) { |
|
104
|
|
|
$this->db->query(' |
|
105
|
|
|
ALTER TABLE `s_plugin_connect_items` |
|
106
|
|
|
ADD COLUMN `exported` TINYINT(1) DEFAULT 0 |
|
107
|
|
|
'); |
|
108
|
|
|
|
|
109
|
|
|
$this->db->query(' |
|
110
|
|
|
UPDATE `s_plugin_connect_items` |
|
111
|
|
|
SET `exported` = 1 |
|
112
|
|
|
WHERE (`export_status` = ? OR `export_status` = ? OR `export_status` = ?) AND `shop_id` IS NULL', |
|
113
|
|
|
[Attribute::STATUS_INSERT, Attribute::STATUS_UPDATE, Attribute::STATUS_SYNCED] |
|
114
|
|
|
); |
|
115
|
|
|
} |
|
116
|
|
|
} |
|
117
|
|
|
|
|
118
|
|
|
private function removeRedirectMenu() |
|
119
|
|
|
{ |
|
120
|
|
|
if (version_compare($this->version, '1.0.4', '<=')) { |
|
121
|
|
|
$connectItem = $this->bootstrap->Menu()->findOneBy(['label' => 'Open Connect', 'action' => '']); |
|
122
|
|
|
if ($connectItem) { |
|
123
|
|
|
$this->modelManager->remove($connectItem); |
|
124
|
|
|
$this->modelManager->flush(); |
|
125
|
|
|
} |
|
126
|
|
|
} |
|
127
|
|
|
} |
|
128
|
|
|
|
|
129
|
|
|
private function updateConnectAttribute() |
|
130
|
|
|
{ |
|
131
|
|
|
if (version_compare($this->version, '1.0.6', '<=')) { |
|
132
|
|
|
$result = $this->db->query("SELECT value FROM s_plugin_connect_config WHERE name = 'connectAttribute'"); |
|
133
|
|
|
$row = $result->fetch(); |
|
134
|
|
|
$attr = 19; |
|
135
|
|
|
if ($row) { |
|
136
|
|
|
$attr = $row['value']; |
|
137
|
|
|
} |
|
138
|
|
|
|
|
139
|
|
|
$this->db->query(' |
|
140
|
|
|
UPDATE `s_articles_attributes` |
|
141
|
|
|
SET `connect_reference` = `attr' . $attr . '` |
|
142
|
|
|
WHERE connect_reference IS NULL; |
|
143
|
|
|
'); |
|
144
|
|
|
|
|
145
|
|
|
$this->db->query("DELETE FROM s_plugin_connect_config WHERE name = 'connectAttribute'"); |
|
146
|
|
|
} |
|
147
|
|
|
} |
|
148
|
|
|
|
|
149
|
|
|
private function addConnectDescriptionElement() |
|
150
|
|
|
{ |
|
151
|
|
|
if (version_compare($this->version, '1.0.9', '<=')) { |
|
152
|
|
|
$tableName = $this->modelManager->getClassMetadata('Shopware\Models\Attribute\Article')->getTableName(); |
|
153
|
|
|
$columnName = 'connect_product_description'; |
|
154
|
|
|
|
|
155
|
|
|
$repo = $this->modelManager->getRepository('Shopware\Models\Attribute\Configuration'); |
|
156
|
|
|
$element = $repo->findOneBy([ |
|
157
|
|
|
'tableName' => $tableName, |
|
158
|
|
|
'columnName' => $columnName, |
|
159
|
|
|
]); |
|
160
|
|
|
|
|
161
|
|
|
if (!$element) { |
|
162
|
|
|
$element = new Configuration(); |
|
163
|
|
|
$element->setTableName($tableName); |
|
164
|
|
|
$element->setColumnName($columnName); |
|
165
|
|
|
} |
|
166
|
|
|
|
|
167
|
|
|
$element->setColumnType('html'); |
|
168
|
|
|
$element->setTranslatable(true); |
|
169
|
|
|
$element->setLabel('Connect Beschreibung'); |
|
170
|
|
|
$element->setDisplayInBackend(true); |
|
171
|
|
|
|
|
172
|
|
|
$this->modelManager->persist($element); |
|
173
|
|
|
$this->modelManager->flush(); |
|
174
|
|
|
} |
|
175
|
|
|
} |
|
176
|
|
|
|
|
177
|
|
|
private function updateProductDescriptionSetting() |
|
178
|
|
|
{ |
|
179
|
|
|
if (version_compare($this->version, '1.0.9', '<=')) { |
|
180
|
|
|
//migrates to the new export settings |
|
181
|
|
|
$result = $this->db->query("SELECT `value` FROM s_plugin_connect_config WHERE name = 'alternateDescriptionField'"); |
|
182
|
|
|
$row = $result->fetch(); |
|
183
|
|
|
|
|
184
|
|
|
if ($row) { |
|
185
|
|
|
$mapper = [ |
|
186
|
|
|
'a.description' => BaseProductQuery::SHORT_DESCRIPTION_FIELD, |
|
187
|
|
|
'a.descriptionLong' => BaseProductQuery::LONG_DESCRIPTION_FIELD, |
|
188
|
|
|
'attribute.connectProductDescription' => BaseProductQuery::CONNECT_DESCRIPTION_FIELD, |
|
189
|
|
|
]; |
|
190
|
|
|
|
|
191
|
|
|
if ($name = $mapper[$row['value']]) { |
|
192
|
|
|
$result = $this->db->query("SELECT `id` FROM s_plugin_connect_config WHERE name = '$name'"); |
|
193
|
|
|
$row = $result->fetch(); |
|
194
|
|
|
|
|
195
|
|
|
$id = null; |
|
196
|
|
|
if (isset($row['id'])) { |
|
197
|
|
|
$id = $row['id']; |
|
198
|
|
|
} |
|
199
|
|
|
|
|
200
|
|
|
$this->db->query( |
|
201
|
|
|
"REPLACE INTO `s_plugin_connect_config` |
|
202
|
|
|
(`id`, `name`, `value`, `shopId`, `groupName`) |
|
203
|
|
|
VALUES |
|
204
|
|
|
(?, ?, 1, null, 'export')", |
|
205
|
|
|
[$id, $name] |
|
206
|
|
|
); |
|
207
|
|
|
} |
|
208
|
|
|
} |
|
209
|
|
|
|
|
210
|
|
|
$this->db->query(" |
|
211
|
|
|
ALTER TABLE `s_plugin_connect_items` |
|
212
|
|
|
ADD `update_additional_description` VARCHAR(255) NULL DEFAULT 'inherit' AFTER `update_short_description`; |
|
213
|
|
|
"); |
|
214
|
|
|
} |
|
215
|
|
|
} |
|
216
|
|
|
|
|
217
|
|
|
private function createUpdateAdditionalDescriptionColumn() |
|
218
|
|
|
{ |
|
219
|
|
|
// for some reason update_additional_description column is missing in 1.0.11 |
|
220
|
|
|
if (version_compare($this->version, '1.0.11', '<=')) { |
|
221
|
|
|
try { |
|
222
|
|
|
$this->db->query(" |
|
223
|
|
|
ALTER TABLE `s_plugin_connect_items` |
|
224
|
|
|
ADD `update_additional_description` VARCHAR(255) NULL DEFAULT 'inherit' AFTER `update_short_description`; |
|
225
|
|
|
"); |
|
226
|
|
|
} catch (\Exception $e) { |
|
227
|
|
|
// ignore it if the column already exists |
|
228
|
|
|
} |
|
229
|
|
|
} |
|
230
|
|
|
} |
|
231
|
|
|
|
|
232
|
|
|
private function createDynamicStreamTable() |
|
233
|
|
|
{ |
|
234
|
|
|
if (version_compare($this->version, '1.0.12', '<=')) { |
|
235
|
|
|
$query = "CREATE TABLE IF NOT EXISTS `s_plugin_connect_streams_relation` ( |
|
236
|
|
|
`stream_id` int(11) unsigned NOT NULL, |
|
237
|
|
|
`article_id` int(11) unsigned NOT NULL, |
|
238
|
|
|
`deleted` int(1) NOT NULL DEFAULT '0', |
|
239
|
|
|
UNIQUE KEY `stream_id` (`stream_id`,`article_id`), |
|
240
|
|
|
CONSTRAINT s_plugin_connect_streams_selection_fk_stream_id FOREIGN KEY (stream_id) REFERENCES s_product_streams (id) ON DELETE CASCADE, |
|
241
|
|
|
CONSTRAINT s_plugin_connect_streams_selection_fk_article_id FOREIGN KEY (article_id) REFERENCES s_articles (id) ON DELETE CASCADE |
|
242
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;"; |
|
243
|
|
|
|
|
244
|
|
|
$this->db->exec($query); |
|
245
|
|
|
} |
|
246
|
|
|
} |
|
247
|
|
|
|
|
248
|
|
|
private function addOrderStatus() |
|
249
|
|
|
{ |
|
250
|
|
|
if (version_compare($this->version, '1.0.12', '<=')) { |
|
251
|
|
|
$query = $this->modelManager->getRepository('Shopware\Models\Order\Status')->createQueryBuilder('s'); |
|
252
|
|
|
$query->select('MAX(s.id)'); |
|
253
|
|
|
$result = $query->getQuery()->getOneOrNullResult(); |
|
254
|
|
|
|
|
255
|
|
|
if (count($result) > 0) { |
|
256
|
|
|
$currentId = (int) reset($result); |
|
257
|
|
|
} else { |
|
258
|
|
|
$currentId = 0; |
|
259
|
|
|
} |
|
260
|
|
|
|
|
261
|
|
|
$name = ConnectOrderUtil::ORDER_STATUS_ERROR; |
|
262
|
|
|
$group = Status::GROUP_STATE; |
|
263
|
|
|
|
|
264
|
|
|
$isExists = $this->db->query(' |
|
265
|
|
|
SELECT `id` FROM `s_core_states` |
|
266
|
|
|
WHERE `name` = ? AND `group` = ? |
|
267
|
|
|
', [$name, $group] |
|
268
|
|
|
)->fetch(); |
|
269
|
|
|
|
|
270
|
|
|
if ($isExists) { |
|
271
|
|
|
return; |
|
272
|
|
|
} |
|
273
|
|
|
|
|
274
|
|
|
++$currentId; |
|
275
|
|
|
$this->db->query(' |
|
276
|
|
|
INSERT INTO `s_core_states` |
|
277
|
|
|
(`id`, `name`, `description`, `position`, `group`, `mail`) |
|
278
|
|
|
VALUES (?, ?, ?, ?, ?, ?) |
|
279
|
|
|
', [$currentId, $name, 'SC error', $currentId, $group, 0] |
|
280
|
|
|
); |
|
281
|
|
|
} |
|
282
|
|
|
} |
|
283
|
|
|
|
|
284
|
|
|
/** |
|
285
|
|
|
* Replace longDescriptionField and shortDescription values, |
|
286
|
|
|
* because of wrong snippets in previous versions. |
|
287
|
|
|
* |
|
288
|
|
|
* ExtJs view show longDescription label, but the value was stored as shortDescription |
|
289
|
|
|
*/ |
|
290
|
|
|
private function fixExportDescriptionSettings() |
|
291
|
|
|
{ |
|
292
|
|
|
if (version_compare($this->version, '1.0.12', '<=')) { |
|
293
|
|
|
$rows = $this->db->fetchPairs( |
|
294
|
|
|
'SELECT `name`, `value` FROM s_plugin_connect_config WHERE name = ? OR name = ?', |
|
295
|
|
|
['longDescriptionField', 'shortDescriptionField'] |
|
296
|
|
|
); |
|
297
|
|
|
|
|
298
|
|
|
if (!array_key_exists('longDescriptionField', $rows) || !array_key_exists('shortDescriptionField', $rows)) { |
|
299
|
|
|
return; |
|
300
|
|
|
} |
|
301
|
|
|
|
|
302
|
|
|
if (($rows['longDescriptionField'] == 1 && $rows['shortDescriptionField'] == 1) |
|
303
|
|
|
|| ($rows['longDescriptionField'] == 0 && $rows['shortDescriptionField'] == 0)) { |
|
304
|
|
|
return; |
|
305
|
|
|
} |
|
306
|
|
|
|
|
307
|
|
|
$newValues = [ |
|
308
|
|
|
'longDescriptionField' => $rows['shortDescriptionField'], |
|
309
|
|
|
'shortDescriptionField' => $rows['longDescriptionField'], |
|
310
|
|
|
]; |
|
311
|
|
|
|
|
312
|
|
|
$this->db->query(' |
|
313
|
|
|
UPDATE `s_plugin_connect_config` |
|
314
|
|
|
SET `value` = ? |
|
315
|
|
|
WHERE `name` = ?', |
|
316
|
|
|
[$newValues['longDescriptionField'], 'longDescriptionField'] |
|
317
|
|
|
); |
|
318
|
|
|
|
|
319
|
|
|
$this->db->query(' |
|
320
|
|
|
UPDATE `s_plugin_connect_config` |
|
321
|
|
|
SET `value` = ? |
|
322
|
|
|
WHERE `name` = ?', |
|
323
|
|
|
[$newValues['shortDescriptionField'], 'shortDescriptionField'] |
|
324
|
|
|
); |
|
325
|
|
|
} |
|
326
|
|
|
} |
|
327
|
|
|
|
|
328
|
|
|
private function fixMarketplaceUrl() |
|
329
|
|
|
{ |
|
330
|
|
|
if (version_compare($this->version, '1.0.12', '<=')) { |
|
331
|
|
|
$repo = $this->modelManager->getRepository('Shopware\Models\Config\Form'); |
|
332
|
|
|
/** @var \Shopware\Models\Config\Form $form */ |
|
333
|
|
|
$form = $repo->findOneBy([ |
|
334
|
|
|
'name' => 'SwagConnect', |
|
335
|
|
|
]); |
|
336
|
|
|
|
|
337
|
|
|
if (!$form) { |
|
338
|
|
|
return; |
|
339
|
|
|
} |
|
340
|
|
|
|
|
341
|
|
|
/** @var \Shopware\Models\Config\Element $element */ |
|
342
|
|
|
foreach ($form->getElements() as $element) { |
|
343
|
|
|
if ($element->getName() != 'connectDebugHost') { |
|
344
|
|
|
continue; |
|
345
|
|
|
} |
|
346
|
|
|
|
|
347
|
|
View Code Duplication |
if (strlen($element->getValue()) > 0 && strpos($element->getValue(), 'sn.') === false) { |
|
|
|
|
|
|
348
|
|
|
$element->setValue('sn.' . $element->getValue()); |
|
349
|
|
|
$this->modelManager->persist($element); |
|
350
|
|
|
} |
|
351
|
|
|
|
|
352
|
|
|
$values = $element->getValues(); |
|
353
|
|
|
if (count($values) > 0) { |
|
354
|
|
|
/** @var \Shopware\Models\Config\Value $element */ |
|
355
|
|
|
$value = $values[0]; |
|
356
|
|
View Code Duplication |
if (strlen($value->getValue()) > 0 && strpos($value->getValue(), 'sn.') === false) { |
|
|
|
|
|
|
357
|
|
|
$value->setValue('sn.' . $value->getValue()); |
|
358
|
|
|
$this->modelManager->persist($value); |
|
359
|
|
|
} |
|
360
|
|
|
} |
|
361
|
|
|
|
|
362
|
|
|
$this->modelManager->flush(); |
|
363
|
|
|
} |
|
364
|
|
|
} |
|
365
|
|
|
} |
|
366
|
|
|
|
|
367
|
|
|
private function addIndexToChangeTable() |
|
368
|
|
|
{ |
|
369
|
|
|
if (version_compare($this->version, '1.0.16', '<=')) { |
|
370
|
|
|
$this->db->query(' |
|
371
|
|
|
ALTER TABLE `sw_connect_change` |
|
372
|
|
|
ADD INDEX `c_operation` (`c_operation`) |
|
373
|
|
|
'); |
|
374
|
|
|
} |
|
375
|
|
|
} |
|
376
|
|
|
|
|
377
|
|
|
/** |
|
378
|
|
|
* In some cases Connect main menu was duplicated |
|
379
|
|
|
* when shop is connected to SEM project. All not needed menu items must be removed. |
|
380
|
|
|
*/ |
|
381
|
|
|
private function removeDuplicatedMenuItems() |
|
382
|
|
|
{ |
|
383
|
|
|
if (version_compare($this->version, '1.0.16', '<=')) { |
|
384
|
|
|
$mainMenuItems = $this->bootstrap->Menu()->findBy([ |
|
385
|
|
|
'class' => Menu::CONNECT_CLASS, |
|
386
|
|
|
'parent' => null, |
|
387
|
|
|
], ['id' => 'ASC']); |
|
388
|
|
|
|
|
389
|
|
|
foreach (array_slice($mainMenuItems, 1) as $menuItem) { |
|
390
|
|
|
foreach ($menuItem->getChildren() as $children) { |
|
391
|
|
|
$this->modelManager->remove($children); |
|
392
|
|
|
} |
|
393
|
|
|
|
|
394
|
|
|
$this->modelManager->remove($menuItem); |
|
395
|
|
|
} |
|
396
|
|
|
$this->modelManager->flush(); |
|
397
|
|
|
} |
|
398
|
|
|
} |
|
399
|
|
|
|
|
400
|
|
|
/** |
|
401
|
|
|
* Create an index by source_id and shop_id. |
|
402
|
|
|
* It's most used combination to search for products in this table |
|
403
|
|
|
*/ |
|
404
|
|
|
private function addConnectItemsIndex() |
|
405
|
|
|
{ |
|
406
|
|
|
if (version_compare($this->version, '1.1.1', '<=')) { |
|
407
|
|
|
try { |
|
408
|
|
|
$this->db->query('ALTER TABLE s_plugin_connect_items ADD INDEX source_id (source_id, shop_id)'); |
|
409
|
|
|
} catch (\Exception $e) { |
|
410
|
|
|
// ignore it if exists |
|
411
|
|
|
} |
|
412
|
|
|
} |
|
413
|
|
|
} |
|
414
|
|
|
} |
|
415
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.