Completed
Push — development ( 67765c...7029e6 )
by Andrij
18:12
created

Categories::getPathsAndParents()   C

Complexity

Conditions 7
Paths 45

Size

Total Lines 47
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 29
nc 45
nop 0
dl 0
loc 47
rs 6.7272
c 0
b 0
f 0
1
<?php
2
3
namespace exchange\classes;
4
5
use CMSFactory\ModuleSettings;
6
use core\models\Route;
7
use core\models\RouteQuery;
8
use Propel\Runtime\Exception\PropelException;
9
10
/**
11
 *
12
 *
13
 *
14
 * @author kolia
15
 */
16
final class Categories extends ExchangeBase
17
{
0 ignored issues
show
introduced by
Opening brace of a class must be on the same line as the definition
Loading history...
18
19
    /**
20
     *
21
     * @var array
22
     */
23
    private $categoriesNames = [];
24
25
    /**
26
     * Parsed categories from XML to one-dimension array
27
     * @var array
28
     */
29
    private $categoriesXml = [];
30
31
    /**
32
     *
33
     * @var array
34
     */
35
    private $existing = [];
36
37
    /**
0 ignored issues
show
introduced by
Doc comment is empty
Loading history...
38
     *
39
     */
40
    private $externalIds;
41
42
    /**
43
     *
44
     * @var array
45
     */
46
    private $new = [];
47
48
    /**
49
     * Check if category exists (by external id) (helper)
50
     * @param string $externalId
51
     * @param boolean $returnCategoryId if TRUE, then method will return id of category
52
     * @return boolean|int FALSE if category is new, TRUE otherwise
53
     */
54
    public function categoryExists2($externalId, $returnCategoryId = FALSE) {
55
56
        if (null === $this->externalIds) {
57
            $this->externalIds = [];
58
            foreach ($this->categories as $categoryId => $categoryData) {
0 ignored issues
show
Bug introduced by
The property categories does not seem to exist. Did you mean categoriesNames?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
59
                if (!empty($categoryData['external_id'])) {
60
                    $this->externalIds[$categoryData['external_id']] = $categoryId;
61
                }
62
            }
63
        }
64
        $exists = isset($this->externalIds[$externalId]);
65
        if ($exists == TRUE) {
66
            return $returnCategoryId !== TRUE ? TRUE : $this->externalIds[$externalId];
67
        }
68
        return FALSE;
69
    }
70
71
    /**
72
     * Starting import of the categories
73
     * @return boolean|array FALSE|array(count of inserted, count of deleted)
0 ignored issues
show
Documentation introduced by
Should the return type not be boolean|array|null? Also, consider making the array more specific, something like array<String>, or String[].

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

If the return type contains the type array, this check recommends the use of a more specific type like String[] or array<String>.

Loading history...
introduced by
@return doc comment specified, but function has no return statement
Loading history...
74
     * @throws \Exception
0 ignored issues
show
introduced by
Comment missing or not on the next line for @throws tag in function comment
Loading history...
75
     */
76
    protected function import_() {
77
78
        // getting categories names for checking fr unique names
79
        $categoriesI18n = $this->db
80
            ->where('locale', \MY_Controller::getCurrentLocale())
81
            ->get('shop_category_i18n')
82
            ->result_array();
83
84
        /** @var array $categoriesI18n */
85
        foreach ($categoriesI18n as $category) {
86
            array_push($this->categoriesNames, $category['name']);
87
        }
88
        // creating one-dimention array of categories
89
        $this->processCategories($this->importData);
90
91
        // inserting
92
        $insertCount = count($this->new);
93
        if ($insertCount > 0) {
94
            $dbArray = $this->getPreparedData($this->new);
95
            $this->insertBatch('shop_category', $dbArray);
96
            $this->dataLoad->getNewData('categories');
97
            $i18nData = $this->getI18nData($this->new);
98
            $this->insertBatch('shop_category_i18n', $i18nData);
99
        }
100
101
        $ignoreExisting = ModuleSettings::ofModule('exchange')->get('ignore_existing');
102
        // updating
103
        $updateCount = count($this->existing);
104
        if ($updateCount > 0 && !isset($ignoreExisting['categories'])) {
105
            $dbArray = $this->getPreparedData($this->existing);
106
            $this->updateBatch('shop_category', $dbArray, 'external_id');
107
            $this->dataLoad->getNewData('categories');
108
            $i18nData = $this->getI18nData($this->existing);
109
            $this->updateBatch('shop_category_i18n', $i18nData, 'id');
110
        }
111
112
        $pathsAndParents = $this->getPathsAndParents();
113
        $this->updateBatch('shop_category', $pathsAndParents, 'id');
114
115
        $this->dataLoad->getNewData('categories');
116
    }
117
118
    /**
119
     * Creates one-dimension array with categories from XML-file
120
     * (method is filling  $categories, $new and $existing arrays of class instance)
121
     * @param \SimpleXMLElement $categories
122
     * @param string $parent (default null) external id of parent if there is
123
     */
124
    private function processCategories(\SimpleXMLElement $categories, $parent = NULL) {
125
        foreach ($categories as $category) {
126
            $externalId = (string) $category->Ид;
127
128
            // splitting on those which need to be updated and new (by external id)
129
            if (FALSE == $this->categoryExists($externalId)) {
130
                $this->new[] = $externalId;
131
                $name = $this->getCategoryName((string) $category->Наименование);
132
            } else {
133
                $this->existing[] = $externalId;
134
                $name = (string) $category->Наименование;
135
            }
136
137
            $this->categoriesXml[$externalId] = [
138
                                                 'name'               => $name,
139
                                                 'active'             => (string) $category->Статус === 'Удален' ? 0 : 1,
140
                                                 'external_id'        => $externalId,
141
                                                 'parent_external_id' => $parent === null ? 0 : $parent,
142
                                                ];
143
144
            if (isset($category->Группы)) {
145
                $this->processCategories($category->Группы->Группа, $externalId);
146
            }
147
        }
148
149
    }
150
151
    /**
152
     * Check if category exists (by external id) (helper)
153
     * @param string $externalId
154
     * @return boolean FALSE if category is new, FALSE otherwise
155
     */
156
    public function categoryExists($externalId) {
157
158
        foreach ($this->categories as $categoryId => $categoryData) {
0 ignored issues
show
Bug introduced by
The property categories does not seem to exist. Did you mean categoriesNames?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
159
            if ($externalId == $categoryData['external_id']) {
160
                return TRUE;
161
            }
162
        }
163
        return FALSE;
164
    }
165
166
    /**
167
     * @param string $name
168
     * @return string
169
     */
170
    private function getCategoryName($name) {
171
172
        $nameTemp = $name;
173
        $i = 1;
174
        while (in_array($nameTemp, $this->categoriesNames, true)) {
175
            $nameTemp = $name . ' ' . $i++;
176
        }
177
        array_push($this->categoriesNames, $nameTemp);
178
        return $nameTemp;
179
    }
180
181
    /**
182
     * Prepare array for DB insert/update query
183
     * (returns array ready to inserting in database)
184
     * @param array $categoriesExternalIds
185
     * @return array
186
     */
187
    private function getPreparedData(array $categoriesExternalIds) {
188
189
        $dbArray = [];
190
        foreach ($categoriesExternalIds as $externalId) {
191
            // fitment of category url (might be busy)
192
            // preparing array for insert
193
            $dbArray[] = [
194
                          'external_id' => $externalId,
195
                          'active'      => $this->categoriesXml[$externalId]['active'],
196
                         ];
197
        }
198
        return $dbArray;
199
    }
200
201
    /**
202
     * @param array $categoriesExternalIds
203
     * @return array
204
     */
205
    private function getI18nData($categoriesExternalIds) {
206
207
        $i18n = [];
208
        foreach ($this->categories as $categoryId => $categoryData) {
0 ignored issues
show
Bug introduced by
The property categories does not seem to exist. Did you mean categoriesNames?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
209
            if (in_array($categoryData['external_id'], $categoriesExternalIds, true)) {
210
                $i18n[] = [
211
                           'id'     => $categoryData['id'],
212
                           'locale' => $this->locale,
213
                           'name'   => $this->categoriesXml[$categoryData['external_id']]['name'],
214
                          ];
215
            }
216
        }
217
        return $i18n;
218
    }
219
220
    /**
221
     * Filling parent ids of
222
     * @return array
223
     */
224
    private function getPathsAndParents() {
225
        $categoriesExternalIds = array_merge($this->new, $this->existing);
226
        // UPDATING INSERTED CATEGORIES (add parent ids & full path)
227
        $this->dataLoad->getNewData('categories'); // getting categories form db again
228
        // getting only categories which was inserted
229
        $categories = [];
230
        // "parent data" is in $this->categories (db),
231
        foreach ($this->categories as $categoryId => $categoryData) {
0 ignored issues
show
Bug introduced by
The property categories does not seem to exist. Did you mean categoriesNames?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
232
            if (in_array($categoryData['external_id'], $categoriesExternalIds, true)) {
233
                $categories[$categoryData['id']] = [
234
                                                    'id'          => $categoryData['id'],
235
                                                    'parent_id'   => $this->getParentIdDb($categoryData['external_id']),
236
                                                    'external_id' => $categoryData['external_id'],
237
                                                   ];
238
            }
239
        }
240
241
        // creating id-paths and url-paths of each category
242
        foreach ($categories as $categoryId => $categoryData) {
243
            $currentPathIds = [];
244
245
            $neededCid = $categoryData['parent_id'];
246
247
            while ($neededCid != 0) {
248
                $currentPathIds[] = $neededCid;
249
                $neededCid = $categories[$neededCid]['parent_id'];
250
            }
251
252
            $parentUrl = RouteQuery::create()->filterByEntityId($categoryData['parent_id'])->filterByType(Route::TYPE_SHOP_CATEGORY)->findOne();
253
            try{
254
255
                        $route = new RouteQuery();
256
                        $route->filterByParentUrl($parentUrl ? $parentUrl->getFullUrl() : '');
257
                        $route->filterByUrl(translit_url($this->categoriesXml[$categoryData['external_id']]['name']));
258
                        $route->findByType(Route::TYPE_SHOP_CATEGORY);
259
                        $route->filterByEntityId($categoryData['id']);
260
                        $route->findOneOrCreate()->save();
261
262
            }catch (PropelException $exp){
263
                dd($exp);
0 ignored issues
show
Coding Style introduced by
The use of function dd() is forbidden
Loading history...
264
            }
265
            $categories[$categoryId]['route_id'] = $route->findOne()->getId();
266
            $categories[$categoryId]['full_path_ids'] = serialize(array_reverse($currentPathIds));
267
        }
268
269
        return $categories;
270
    }
271
272
    /**
273
     * Returning DB id of category by external_id (helper)
274
     * @param string $externalId
275
     * @return int|boolean id (DB primary key) of category|FALSE
276
     */
277
    private function getParentIdDb($externalId) {
278
279
        $parentExternalId = $this->categoriesXml[$externalId]['parent_external_id'];
280
        if ((string) $parentExternalId == '0') {
281
            return 0;
282
        }
283
        foreach ($this->categories as $categoryData) {
0 ignored issues
show
Bug introduced by
The property categories does not seem to exist. Did you mean categoriesNames?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
284
            if ($parentExternalId == $categoryData['external_id']) {
285
                return $categoryData['id'];
286
            }
287
        }
288
        return 0;
289
    }
290
291
}