Completed
Pull Request — master (#352)
by Stefan
04:21
created

Update::removeDuplicatedMenuItems()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 18
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 18
rs 9.2
c 0
b 0
f 0
cc 4
eloc 11
nc 4
nop 0
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
use ShopwarePlugins\Connect\Components\Logger;
18
19
/**
20
 * Updates existing versions of the plugin
21
 *
22
 * Class Update
23
 * @package ShopwarePlugins\Connect\Bootstrap
24
 */
25
class Update
26
{
27
    /**
28
     * @var \Shopware_Plugins_Backend_SwagConnect_Bootstrap
29
     */
30
    protected $bootstrap;
31
32
    /**
33
     * @var Pdo
34
     */
35
    protected $db;
36
37
    /**
38
     * @var ModelManager
39
     */
40
    protected $modelManager;
41
42
    /**
43
     * @var string
44
     */
45
    protected $version;
46
47
    /**
48
     * @var Logger
49
     */
50
    private $logger;
51
52
    /**
53
     * Setup constructor.
54
     * @param \Shopware_Plugins_Backend_SwagConnect_Bootstrap $bootstrap
55
     * @param ModelManager $modelManager
56
     * @param Pdo $db
57
     * @param $version
58
     * @param Logger|null $logger
59
     */
60
    public function __construct(
61
        \Shopware_Plugins_Backend_SwagConnect_Bootstrap $bootstrap,
62
        ModelManager $modelManager,
63
        Pdo $db,
64
        Logger $logger,
65
        $version
66
    ) {
67
        $this->bootstrap = $bootstrap;
68
        $this->modelManager = $modelManager;
69
        $this->db = $db;
70
        $this->logger = $logger;
71
        $this->version = $version;
72
    }
73
74
    public function run()
75
    {
76
        // Force an SDK re-verify
77
        $this->reVerifySDK();
78
79
        $this->createExportedFlag();
80
        $this->removeRedirectMenu();
81
        $this->updateConnectAttribute();
82
        $this->addConnectDescriptionElement();
83
        $this->updateProductDescriptionSetting();
84
        $this->createUpdateAdditionalDescriptionColumn();
85
        $this->createDynamicStreamTable();
86
        $this->addOrderStatus();
87
        $this->fixExportDescriptionSettings();
88
        $this->fixMarketplaceUrl();
89
        $this->addIndexToChangeTable();
90
        $this->removeDuplicatedMenuItems();
91
        $this->addConnectItemsIndex();
92
93
        return true;
94
    }
95
96
    /**
97
     * Forces the SDK to re-verify the API key
98
     */
99
    public function reVerifySDK()
100
    {
101
        $this->db->query('
102
            UPDATE sw_connect_shop_config
103
            SET s_config = ?
104
            WHERE s_shop = "_last_update_"
105
            LIMIT 1; ',
106
            [time() - 8 * 60 * 60 * 24]
107
        );
108
    }
109
110
    private function createExportedFlag()
111
    {
112
        if (version_compare($this->version, '1.0.1', '<=')) {
113
            $this->db->query('
114
                ALTER TABLE `s_plugin_connect_items`
115
                ADD COLUMN `exported` TINYINT(1) DEFAULT 0
116
            ');
117
118
            $this->db->query('
119
                UPDATE `s_plugin_connect_items`
120
                SET `exported` = 1
121
                WHERE (`export_status` = ? OR `export_status` = ? OR `export_status` = ?) AND `shop_id` IS NULL',
122
                [Attribute::STATUS_INSERT, Attribute::STATUS_UPDATE, Attribute::STATUS_SYNCED]
123
            );
124
        }
125
    }
126
127
    private function removeRedirectMenu()
128
    {
129
        if (version_compare($this->version, '1.0.4', '<=')) {
130
            $connectItem = $this->bootstrap->Menu()->findOneBy(['label' => 'Open Connect', 'action' => '']);
131
            if ($connectItem) {
132
                $this->modelManager->remove($connectItem);
133
                $this->modelManager->flush();
134
            }
135
        }
136
    }
137
138
    private function updateConnectAttribute()
139
    {
140
        if (version_compare($this->version, '1.0.6', '<=')) {
141
            $result = $this->db->query("SELECT value FROM s_plugin_connect_config WHERE name = 'connectAttribute'");
142
            $row = $result->fetch();
143
            $attr = 19;
144
            if ($row) {
145
                $attr = $row['value'];
146
            }
147
148
            $this->db->query('
149
                    UPDATE `s_articles_attributes` 
150
                    SET `connect_reference` = `attr' . $attr . '` 
151
                    WHERE connect_reference IS NULL;
152
                ');
153
154
            $this->db->query("DELETE FROM s_plugin_connect_config WHERE name = 'connectAttribute'");
155
        }
156
    }
157
158
    private function addConnectDescriptionElement()
159
    {
160
        if (version_compare($this->version, '1.0.9', '<=')) {
161
            $tableName = $this->modelManager->getClassMetadata('Shopware\Models\Attribute\Article')->getTableName();
162
            $columnName = 'connect_product_description';
163
164
            $repo = $this->modelManager->getRepository('Shopware\Models\Attribute\Configuration');
165
            $element = $repo->findOneBy([
166
                'tableName' => $tableName,
167
                'columnName' => $columnName,
168
            ]);
169
170
            if (!$element) {
171
                $element = new Configuration();
172
                $element->setTableName($tableName);
173
                $element->setColumnName($columnName);
174
            }
175
176
            $element->setColumnType('html');
177
            $element->setTranslatable(true);
178
            $element->setLabel('Connect Beschreibung');
179
            $element->setDisplayInBackend(true);
180
181
            $this->modelManager->persist($element);
182
            $this->modelManager->flush();
183
        }
184
    }
185
186
    private function updateProductDescriptionSetting()
187
    {
188
        if (version_compare($this->version, '1.0.9', '<=')) {
189
            //migrates to the new export settings
190
            $result = $this->db->query("SELECT `value` FROM s_plugin_connect_config WHERE name = 'alternateDescriptionField'");
191
            $row = $result->fetch();
192
193
            if ($row) {
194
                $mapper = [
195
                    'a.description' => BaseProductQuery::SHORT_DESCRIPTION_FIELD,
196
                    'a.descriptionLong' => BaseProductQuery::LONG_DESCRIPTION_FIELD,
197
                    'attribute.connectProductDescription' => BaseProductQuery::CONNECT_DESCRIPTION_FIELD,
198
                ];
199
200
                if ($name = $mapper[$row['value']]) {
201
                    $result = $this->db->query("SELECT `id` FROM s_plugin_connect_config WHERE name = '$name'");
202
                    $row = $result->fetch();
203
204
                    $id = null;
205
                    if (isset($row['id'])) {
206
                        $id = $row['id'];
207
                    }
208
209
                    $this->db->query(
210
                        "REPLACE INTO `s_plugin_connect_config`
211
                        (`id`, `name`, `value`, `shopId`, `groupName`)
212
                        VALUES
213
                        (?, ?, 1, null, 'export')",
214
                        [$id, $name]
215
                    );
216
                }
217
            }
218
219
            $this->db->query("
220
                ALTER TABLE `s_plugin_connect_items`
221
                ADD `update_additional_description` VARCHAR(255) NULL DEFAULT 'inherit' AFTER `update_short_description`;
222
            ");
223
        }
224
    }
225
226
    private function createUpdateAdditionalDescriptionColumn()
227
    {
228
        // for some reason update_additional_description column is missing in 1.0.11
229
        if (version_compare($this->version, '1.0.11', '<=')) {
230
            try {
231
                $this->db->query("
232
                        ALTER TABLE `s_plugin_connect_items`
233
                        ADD `update_additional_description` VARCHAR(255) NULL DEFAULT 'inherit' AFTER `update_short_description`;
234
                    ");
235
            } catch (\Exception $e) {
236
                // ignore it if the column already exists
237
            }
238
        }
239
    }
240
241
    private function createDynamicStreamTable()
242
    {
243
        if (version_compare($this->version, '1.0.12', '<=')) {
244
            $query = "CREATE TABLE IF NOT EXISTS `s_plugin_connect_streams_relation` (
245
                `stream_id` int(11) unsigned NOT NULL,
246
                `article_id` int(11) unsigned NOT NULL,
247
                `deleted` int(1) NOT NULL DEFAULT '0',
248
                UNIQUE KEY `stream_id` (`stream_id`,`article_id`),
249
                CONSTRAINT s_plugin_connect_streams_selection_fk_stream_id FOREIGN KEY (stream_id) REFERENCES s_product_streams (id) ON DELETE CASCADE,
250
                CONSTRAINT s_plugin_connect_streams_selection_fk_article_id FOREIGN KEY (article_id) REFERENCES s_articles (id) ON DELETE CASCADE
251
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;";
252
253
            $this->db->exec($query);
254
        }
255
    }
256
257
    private function addOrderStatus()
258
    {
259
        if (version_compare($this->version, '1.0.12', '<=')) {
260
            $query = $this->modelManager->getRepository('Shopware\Models\Order\Status')->createQueryBuilder('s');
261
            $query->select('MAX(s.id)');
262
            $result = $query->getQuery()->getOneOrNullResult();
263
264
            if (count($result) > 0) {
265
                $currentId = (int) reset($result);
266
            } else {
267
                $currentId = 0;
268
            }
269
270
            $name = ConnectOrderUtil::ORDER_STATUS_ERROR;
271
            $group = Status::GROUP_STATE;
272
273
            $isExists = $this->db->query('
274
                SELECT `id` FROM `s_core_states`
275
                WHERE `name` = ? AND `group` = ?
276
                ', [$name, $group]
277
            )->fetch();
278
279
            if ($isExists) {
280
                return;
281
            }
282
283
            ++$currentId;
284
            $this->db->query('
285
                INSERT INTO `s_core_states`
286
                (`id`, `name`, `description`, `position`, `group`, `mail`)
287
                VALUES (?, ?, ?, ?, ?, ?)
288
                ', [$currentId, $name, 'SC error', $currentId, $group, 0]
289
            );
290
        }
291
    }
292
293
    /**
294
     * Replace longDescriptionField and shortDescription values,
295
     * because of wrong snippets in previous versions.
296
     *
297
     * ExtJs view show longDescription label, but the value was stored as shortDescription
298
     */
299
    private function fixExportDescriptionSettings()
300
    {
301
        if (version_compare($this->version, '1.0.12', '<=')) {
302
            $rows = $this->db->fetchPairs(
303
                'SELECT `name`, `value` FROM s_plugin_connect_config WHERE name = ? OR name = ?',
304
                ['longDescriptionField', 'shortDescriptionField']
305
            );
306
307
            if (!array_key_exists('longDescriptionField', $rows) || !array_key_exists('shortDescriptionField', $rows)) {
308
                return;
309
            }
310
311
            if (($rows['longDescriptionField'] == 1 && $rows['shortDescriptionField'] == 1)
312
                || ($rows['longDescriptionField'] == 0 && $rows['shortDescriptionField'] == 0)) {
313
                return;
314
            }
315
316
            $newValues = [
317
                'longDescriptionField' => $rows['shortDescriptionField'],
318
                'shortDescriptionField' => $rows['longDescriptionField'],
319
            ];
320
321
            $this->db->query('
322
                UPDATE `s_plugin_connect_config`
323
                SET `value` = ?
324
                WHERE `name` = ?',
325
                [$newValues['longDescriptionField'], 'longDescriptionField']
326
            );
327
328
            $this->db->query('
329
                UPDATE `s_plugin_connect_config`
330
                SET `value` = ?
331
                WHERE `name` = ?',
332
                [$newValues['shortDescriptionField'], 'shortDescriptionField']
333
            );
334
        }
335
    }
336
337
    private function fixMarketplaceUrl()
338
    {
339
        if (version_compare($this->version, '1.0.12', '<=')) {
340
            $repo = $this->modelManager->getRepository('Shopware\Models\Config\Form');
341
            /** @var \Shopware\Models\Config\Form $form */
342
            $form = $repo->findOneBy([
343
                'name' => 'SwagConnect',
344
            ]);
345
346
            if (!$form) {
347
                return;
348
            }
349
350
            /** @var \Shopware\Models\Config\Element $element */
351
            foreach ($form->getElements() as $element) {
352
                if ($element->getName() != 'connectDebugHost') {
353
                    continue;
354
                }
355
356 View Code Duplication
                if (strlen($element->getValue()) > 0 && strpos($element->getValue(), 'sn.') === false) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
357
                    $element->setValue('sn.' . $element->getValue());
358
                    $this->modelManager->persist($element);
359
                }
360
361
                $values = $element->getValues();
362
                if (count($values) > 0) {
363
                    /** @var \Shopware\Models\Config\Value $element */
364
                    $value = $values[0];
365 View Code Duplication
                    if (strlen($value->getValue()) > 0 && strpos($value->getValue(), 'sn.') === false) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
366
                        $value->setValue('sn.' . $value->getValue());
367
                        $this->modelManager->persist($value);
368
                    }
369
                }
370
371
                $this->modelManager->flush();
372
            }
373
        }
374
    }
375
376
    private function addIndexToChangeTable()
377
    {
378
        if (version_compare($this->version, '1.0.16', '<=')) {
379
            $this->db->query('
380
              ALTER TABLE `sw_connect_change`
381
              ADD INDEX `c_operation` (`c_operation`)
382
             ');
383
        }
384
    }
385
386
    /**
387
     * In some cases Connect main menu was duplicated
388
     * when shop is connected to SEM project. All not needed menu items must be removed.
389
     */
390
    private function removeDuplicatedMenuItems()
391
    {
392
        if (version_compare($this->version, '1.0.16', '<=')) {
393
            $mainMenuItems = $this->bootstrap->Menu()->findBy([
394
                'class' => Menu::CONNECT_CLASS,
395
                'parent' => null,
396
            ], ['id' => 'ASC']);
397
398
            foreach (array_slice($mainMenuItems, 1) as $menuItem) {
399
                foreach ($menuItem->getChildren() as $children) {
400
                    $this->modelManager->remove($children);
401
                }
402
403
                $this->modelManager->remove($menuItem);
404
            }
405
            $this->modelManager->flush();
406
        }
407
    }
408
409
    /**
410
     * Create an index by source_id and shop_id.
411
     * It's most used combination to search for products in this table
412
     */
413
    private function addConnectItemsIndex()
414
    {
415
        if (version_compare($this->version, '1.1.1', '<=')) {
416
            try {
417
                $this->db->query('ALTER TABLE s_plugin_connect_items ADD INDEX source_id (source_id, shop_id)');
418
            } catch (\Exception $e) {
419
                // ignore it if exists
420
                $this->logger->write(
421
                    true,
422
                    sprintf('An error occurred during update to version %s stacktrace: %s', $this->version, $e->getTraceAsString()),
423
                    $e->getMessage()
424
                );
425
            }
426
        }
427
    }
428
}
429