Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
skutree.php
1<?php
2
4
5use Bitrix\Catalog\Product\PropertyCatalogFeature;
8
9class SkuTree
10{
12 private $iblockInfo;
13 private $propertyCodes;
14 private $defaultValues = [];
15
16 public function __construct(\Bitrix\Catalog\v2\Iblock\IblockInfo $iblockInfo)
17 {
18 if (!$iblockInfo || !$iblockInfo->canHaveSku())
19 {
20 throw new \Bitrix\Main\NotSupportedException(sprintf(
21 'Selected iblock {%s} can not have SKU.', $iblockInfo->getProductIblockId()
22 ));
23 }
24
25 $this->iblockInfo = $iblockInfo;
26 }
27
28 public function setPropertyCodes(array $propertyCodes): void
29 {
30 $this->propertyCodes = $propertyCodes;
31 }
32
33 public function getPropertyCodes(): array
34 {
35 if ($this->propertyCodes === null)
36 {
37 $this->propertyCodes = $this->loadPropertyCodes();
38 }
39
40 return $this->propertyCodes;
41 }
42
43 private function loadPropertyCodes(): array
44 {
45 return PropertyCatalogFeature::getOfferTreePropertyCodes(
46 $this->iblockInfo->getSkuIblockId(),
47 ['CODE' => 'Y']
48 ) ?? [];
49 }
50
51 public function setDefaultValues(array $defaultValues): void
52 {
53 $this->defaultValues = $defaultValues;
54 }
55
56 public function getDefaultValues(): array
57 {
58 return array_merge(
59 [
60 'PICT' => false,
61 'NAME' => '',
62 ],
63 $this->defaultValues
64 );
65 }
66
67 private function prepareProductsOfferTree(array $productIds): array
68 {
69 $offers = $this->getOffersForProductIds($productIds);
70
71 return $this->prepareOfferTreeProperties($offers);
72 }
73
74 public function loadWithSelectedOffers(array $productToOfferMap): array
75 {
76 $productIds = array_keys($productToOfferMap);
77 $products = $this->prepareProductsOfferTree($productIds);
78 $treeProperties = $this->getTreeProperties();
79
80 foreach ($productToOfferMap as $productId => $offerMap)
81 {
82 if (!isset($products[$productId]))
83 {
84 continue;
85 }
86
87 $product =& $products[$productId];
88 $offers = [];
89
90 foreach ((array)$offerMap as $offerId)
91 {
92 $this->editTemplateOfferProps($product, $treeProperties, $offerId);
93 $offers[$offerId] = $product;
94 }
95
96 $product = $offers;
97 }
98
99 unset($product);
100
101 return $products;
102 }
103
104 public function load(array $productIds): array
105 {
106 $products = $this->prepareProductsOfferTree($productIds);
107 $treeProperties = $this->getTreeProperties();
108
109 foreach ($products as &$product)
110 {
111 $this->editTemplateOfferProps($product, $treeProperties);
112 }
113
114 return $products;
115 }
116
117 public function loadJsonOffers(array $productToOfferMap): array
118 {
119 $result = [];
120 $offersMap = $this->loadWithSelectedOffers($productToOfferMap);
121 foreach ($offersMap as $productId => $offers)
122 {
123 $result[$productId] = $result[$productId] ?? [];
124 foreach ((array)$offers as $offerId => $offerData)
125 {
126 $offers = [];
127 foreach ($offerData['OFFERS'] as $offer)
128 {
129 $offers[] = array_intersect_key(
130 $offer,
131 array_flip(['TREE', 'ID'])
132 );
133 }
134
135 $result[$productId][$offerId] = [
136 'SELECTED_VALUES' => $offerData['SELECTED_VALUES'] ?? null,
137 'EXISTING_VALUES_JSON' => Json::encode($offerData['EXISTING_VALUES'] ?? null),
138 'OFFERS_JSON' => Json::encode($offers),
139 'IBLOCK_ID' => $this->iblockInfo->getProductIblockId(),
140 ];
141 }
142 }
143
144 return $result;
145 }
146
147 protected function editTemplateOfferProps(array &$product, array $skuPropList, int $selectedOfferId = null): void
148 {
149 $matrix = [];
150 $newOffers = [];
151 $double = [];
152 $product['OFFERS_PROP'] = false;
153
154 $skuPropCodes = array_keys($skuPropList);
155 $matrixFields = array_fill_keys($skuPropCodes, false);
156
157 foreach ($product['OFFERS'] as $keyOffer => $offer)
158 {
159 if (isset($double[$offer['ID']]))
160 {
161 continue;
162 }
163
164 $row = [];
165 foreach ($skuPropCodes as $code)
166 {
167 $row[$code] = $this->getTemplatePropCell($code, $offer, $matrixFields, $skuPropList);
168 }
169
170 $matrix[$keyOffer] = $row;
171
172 $double[$offer['ID']] = true;
173 $newOffers[$keyOffer] = $offer;
174 }
175
176 $product['OFFERS'] = $newOffers;
177
178 $usedFields = [];
179 $existingValues = [];
180 $sortFields = [];
181
182 foreach ($skuPropCodes as $propCode)
183 {
184 $boolExist = $matrixFields[$propCode];
185 foreach ($matrix as $keyOffer => $row)
186 {
187 if ($boolExist)
188 {
189 $offer =& $product['OFFERS'][$keyOffer];
190 $rowValue = $matrix[$keyOffer][$propCode]['VALUE'];
191 $offer['TREE'][$skuPropList[$propCode]['ID']] = $rowValue;
192
193 if ($selectedOfferId === $offer['ID'])
194 {
195 $product['SELECTED_VALUES'][$skuPropList[$propCode]['ID']] = $rowValue;
196 }
197
198 $offer['SKU_SORT_'.$propCode] = $matrix[$keyOffer][$propCode]['SORT'];
199 $sortFields['SKU_SORT_'.$propCode] = SORT_NUMERIC;
200
201 $usedFields[$propCode] = $skuPropList[$propCode];
202 $existingValues[$propCode][] = $rowValue;
203 }
204 else
205 {
206 unset($matrix[$keyOffer][$propCode]);
207 }
208 }
209 }
210
211 foreach ($existingValues as &$propertyValue)
212 {
213 $propertyValue = array_unique($propertyValue);
214 }
215
216 $product['OFFERS_PROP'] = $usedFields;
217 $product['EXISTING_VALUES'] = $existingValues;
218
219 Collection::sortByColumn($product['OFFERS'], $sortFields);
220 }
221
222 protected function getTemplatePropCell($code, $offer, &$matrixFields, $skuPropList): array
223 {
224 $cell = [
225 'VALUE' => 0,
226 'SORT' => PHP_INT_MAX,
227 'NA' => true,
228 ];
229
230 $skuPropSort = array_column($skuPropList[$code]['VALUES'], 'SORT', 'ID');
231
232 if (isset($offer['DISPLAY_PROPERTIES'][$code]))
233 {
234 $matrixFields[$code] = true;
235 $cell['NA'] = false;
236
237 if ($skuPropList[$code]['USER_TYPE'] === 'directory')
238 {
239 $intValue = $skuPropList[$code]['XML_MAP'][$offer['DISPLAY_PROPERTIES'][$code]['VALUE']] ?? 0;
240 $cell['VALUE'] = $intValue;
241 }
242 elseif ($skuPropList[$code]['PROPERTY_TYPE'] === 'L')
243 {
244 $cell['VALUE'] = (int)$offer['DISPLAY_PROPERTIES'][$code]['VALUE_ENUM_ID'];
245 }
246 elseif ($skuPropList[$code]['PROPERTY_TYPE'] === 'E')
247 {
248 $cell['VALUE'] = (int)$offer['DISPLAY_PROPERTIES'][$code]['VALUE'];
249 }
250
251 $cell['SORT'] = $skuPropSort[$cell['VALUE']];
252 }
253
254 return $cell;
255 }
256
257 private function getOffersForProductIds(array $productIds): array
258 {
259 $productProperty = 'PROPERTY_'.$this->iblockInfo->getSkuPropertyId();
260 $productPropertyValue = $productProperty.'_VALUE';
261
262 $filter = [
263 'IBLOCK_ID' => $this->iblockInfo->getSkuIblockId(),
264 'ACTIVE' => 'Y',
265 'ACTIVE_DATE' => 'Y',
266 'CHECK_PERMISSIONS' => 'N',
267 $productProperty => $productIds,
268 ];
269
270 $offers = [];
271 $iterator = \CIBlockElement::GetList(
272 [],
273 $filter,
274 false,
275 false,
276 [$productProperty, 'ID']
277 );
278 while ($row = $iterator->getNext())
279 {
280 $row['ID'] = (int)$row['ID'];
281 $row['PARENT_PRODUCT_ID'] = (int)$row[$productPropertyValue];
282 $row['PROPERTIES'] = [];
283
284 $offers[$row['ID']] = $row;
285 }
286
287 if (!empty($offers))
288 {
289 \CIBlockElement::GetPropertyValuesArray(
290 $offers,
291 $this->iblockInfo->getSkuIblockId(),
292 $filter,
293 [
294 'ID' => PropertyCatalogFeature::getOfferTreePropertyCodes($this->iblockInfo->getSkuIblockId()),
295 ]
296 );
297 }
298
299 return $offers;
300 }
301
305 public function getTreeProperties(): array
306 {
307 $treeProperties = \CIBlockPriceTools::getTreeProperties(
308 $this->iblockInfo->toArray(),
309 $this->getPropertyCodes(),
310 $this->getDefaultValues()
311 );
312
313 $needValues = [];
314 \CIBlockPriceTools::getTreePropertyValues($treeProperties, $needValues);
315
316 foreach ($treeProperties as &$treeProperty)
317 {
318 if (!empty($treeProperty['VALUES']))
319 {
320 $treeProperty['VALUES'] = array_values($treeProperty['VALUES']);
321 }
322 }
323
324 return $treeProperties;
325 }
326
327 private function prepareOfferTreeProperties(array $offers): array
328 {
329 if (empty($offers))
330 {
331 return [];
332 }
333
334 $products = [];
335
336 foreach ($offers as &$offer)
337 {
338 foreach ($this->getPropertyCodes() as $code)
339 {
340 if (!isset($offer['PROPERTIES'][$code]))
341 continue;
342
343 $prop = &$offer['PROPERTIES'][$code];
344 $boolArr = is_array($prop['VALUE']);
345 if (
346 ($boolArr && !empty($prop['VALUE']))
347 || (!$boolArr && (string)$prop['VALUE'] !== '')
348 )
349 {
350 $offer['DISPLAY_PROPERTIES'][$code] = \CIBlockFormatProperties::GetDisplayValue($offer, $prop);
351 }
352 }
353
354 $products[$offer['PARENT_PRODUCT_ID']]['OFFERS'][] = $offer;
355 }
356 unset($offer);
357
358 return $products;
359 }
360}
editTemplateOfferProps(array &$product, array $skuPropList, int $selectedOfferId=null)
Definition skutree.php:147
loadWithSelectedOffers(array $productToOfferMap)
Definition skutree.php:74
loadJsonOffers(array $productToOfferMap)
Definition skutree.php:117
getTemplatePropCell($code, $offer, &$matrixFields, $skuPropList)
Definition skutree.php:222
setPropertyCodes(array $propertyCodes)
Definition skutree.php:28
__construct(\Bitrix\Catalog\v2\Iblock\IblockInfo $iblockInfo)
Definition skutree.php:16
setDefaultValues(array $defaultValues)
Definition skutree.php:51