Completed
Pull Request — master (#371)
by Sven
03:18
created

AutoCategoryResolver::convertNodeToEntity()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 23
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 23
rs 9.0856
c 0
b 0
f 0
cc 2
eloc 14
nc 2
nop 2
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\Components\CategoryResolver;
9
10
use ShopwarePlugins\Connect\Components\CategoryResolver;
11
use Shopware\CustomModels\Connect\RemoteCategoryRepository;
12
use Shopware\Models\Category\Category;
13
use Shopware\Models\Category\Repository as CategoryRepository;
14
use Shopware\Components\Model\ModelManager;
15
use ShopwarePlugins\Connect\Components\Config;
16
17
class AutoCategoryResolver implements CategoryResolver
18
{
19
    /**
20
     * @var ModelManager
21
     */
22
    private $manager;
23
24
    /**
25
     * @var CategoryRepository
26
     */
27
    private $categoryRepository;
28
29
    /**
30
     * @var \Shopware\CustomModels\Connect\RemoteCategoryRepository
31
     */
32
    private $remoteCategoryRepository;
33
34
    /**
35
     * @var Config
36
     */
37
    private $config;
38
39
    /**
40
     * AutoCategoryResolver constructor.
41
     * @param ModelManager $manager
42
     * @param CategoryRepository $categoryRepository
43
     * @param RemoteCategoryRepository $remoteCategoryRepository
44
     * @param Config $config
45
     */
46
    public function __construct(
47
        ModelManager $manager,
48
        CategoryRepository $categoryRepository,
49
        RemoteCategoryRepository $remoteCategoryRepository,
50
        Config $config
51
    ) {
52
        $this->manager = $manager;
53
        $this->categoryRepository = $categoryRepository;
54
        $this->remoteCategoryRepository = $remoteCategoryRepository;
55
        $this->config = $config;
56
    }
57
58
    /**
59
     * {@inheritdoc}
60
     */
61
    public function resolve(array $categories)
62
    {
63
        $tree = $this->generateTree($categories);
64
65
        // we need to foreach, cause we may have two main nodes
66
        // example:
67
        // Deutsch/Category/Subcategory
68
        // English/Category/Subcategory
69
        $remoteCategories = [];
70
        foreach ($tree as $node) {
71
            $mainCategory = $this->categoryRepository->findOneBy([
72
                'name' => $node['name'],
73
                'parentId' => 1,
74
            ]);
75
76
            $remoteCategories = array_merge($remoteCategories, $this->convertTreeToEntities($node['children'], $mainCategory));
77
        }
78
79
        // Collect all, not only leaf categories. Some customers use them to assign products.
80
        // Do not fetch them from database by name as before.
81
        // it is possible to have more than one subcategory "Boots" - CON-4589
82
        return array_map(function ($category) {
83
            return $category['model'];
84
        }, $remoteCategories);
85
    }
86
87
    /**
88
     * Loop categories tree recursive and
89
     * create same structure with entities
90
     *
91
     * @param array $node
92
     * @param null Category $parent
93
     * @param array $categories
94
     * @return array
95
     */
96
    public function convertTreeToEntities(array $node, Category $parent = null, $categories = [])
97
    {
98
        if (!$parent) {
99
            //full load of category entity
100
            $parent = $this->config->getDefaultShopCategory();
101
        }
102
103
        foreach ($node as $category) {
104
            $categoryModel = $this->categoryRepository->findOneBy([
105
                'name' => $category['name'],
106
                'parentId' => $parent->getId()
107
            ]);
108
109
            if (!$categoryModel) {
110
                $categoryModel = $this->convertNodeToEntity($category, $parent);
111
            }
112
113
            $categories[] = [
114
                'model' => $categoryModel,
115
                'categoryKey' => $category['categoryId'],
116
            ];
117
118
            if (!empty($category['children'])) {
119
                $categories = $this->convertTreeToEntities($category['children'], $categoryModel, $categories);
120
            }
121
        }
122
123
        return $categories;
124
    }
125
126
    /**
127
     * Loop through category tree and fetch ids
128
     *
129
     * @param array $node
130
     * @param array $categories
131
     * @return array
132
     */
133
    public function convertTreeToKeys(array $node, $categories = [])
134
    {
135
        foreach ($node as $category) {
136
            $categories[] = [
137
                'categoryKey' => $category['categoryId'],
138
            ];
139
140
            if (!empty($category['children'])) {
141
                $categories = $this->convertTreeToKeys($category['children'], $categories);
142
            }
143
        }
144
145
        return $categories;
146
    }
147
148
    /**
149
     * @param array $category
150
     * @param Category $parent
151
     * @return Category
152
     */
153
    public function convertNodeToEntity(array $category, Category $parent)
154
    {
155
        $categoryModel = new Category();
156
        $categoryModel->fromArray($this->getCategoryData($category['name']));
157
        $categoryModel->setParent($parent);
158
159
        $this->manager->persist($categoryModel);
160
161
        $categoryAttribute = $categoryModel->getAttribute();
162
        $categoryAttribute->setConnectImportedCategory(true);
163
        $this->manager->persist($categoryAttribute);
164
165
        /** @var \Shopware\CustomModels\Connect\RemoteCategory $remoteCategory */
166
        $remoteCategory = $this->remoteCategoryRepository->findOneBy(['categoryKey' => $category['categoryId']]);
167
        if ($remoteCategory) {
168
            $remoteCategory->addLocalCategory($categoryModel);
169
            $this->manager->persist($remoteCategory);
170
        }
171
172
        $this->manager->flush();
173
174
        return $categoryModel;
175
    }
176
177
    /**
178
     * {@inheritdoc}
179
     */
180
    public function generateTree(array $categories, $idPrefix = '')
181
    {
182
        $tree = [];
183
        uksort($categories, function ($a, $b) {
184
            return strlen($a) - strlen($b);
185
        });
186
187
        if (strlen($idPrefix) > 0) {
188
            // find child categories by given prefix
189
            $childCategories = array_filter(array_keys($categories), function ($key) use ($idPrefix) {
190
                return strpos($key, $idPrefix) === 0 && strrpos($key, '/') === strlen($idPrefix);
191
            });
192
            $filteredCategories = array_intersect_key($categories, array_flip($childCategories));
193
        } else {
194
            // filter only main categories
195
            $matchedKeys = array_filter(array_keys($categories), function ($key) {
196
                return strrpos($key, '/') === 0;
197
            });
198
            $filteredCategories = array_intersect_key($categories, array_flip($matchedKeys));
199
        }
200
201
        foreach ($filteredCategories as $key => $categoryName) {
202
            $children = $this->generateTree($categories, $key);
203
            $tree[$key] = [
204
                'name' => $categoryName,
205
                'children' => $children,
206
                'categoryId' => $key,
207
                'leaf' => empty($children),
208
            ];
209
        }
210
211
        return $tree;
212
    }
213
214
    public function storeRemoteCategories(array $categories, $articleId)
215
    {
216
        // Shops connected to SEM projects don't need to store Shopware Connect categories
217
    }
218
219
    /**
220
     * Generate category data array
221
     * it's used to create category and
222
     * attribute from array
223
     *
224
     * @param string $name
225
     * @return array
226
     */
227
    private function getCategoryData($name)
228
    {
229
        return [
230
            'name' => $name,
231
            'active' => true,
232
            'childrenCount' => 0,
233
            'text' => $name,
234
            'attribute' => [
235
                    'id' => 0,
236
                    'parent' => 0,
237
                    'name' => 'Deutsch',
238
                    'position' => 0,
239
                    'active' => true,
240
                    'childrenCount' => 0,
241
                    'text' => '',
242
                    'cls' => '',
243
                    'leaf' => false,
244
                    'allowDrag' => false,
245
                    'parentId' => 0,
246
                    'categoryId' => null,
247
                    'attribute1' => null,
248
                    'attribute2' => null,
249
                    'attribute3' => null,
250
                    'attribute4' => null,
251
                    'attribute5' => null,
252
                    'attribute6' => null,
253
                ],
254
        ];
255
    }
256
}
257