Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
BaseIblockElementRepository.php
1<?php
2
3namespace Bitrix\Catalog\v2;
4
12
22{
24 protected $factory;
26 protected $iblockInfo;
27
28 private ?string $detailUrlTemplate = null;
29
30 private bool $allowedDetailUrl;
31
39 {
40 $this->factory = $factory;
41 $this->iblockInfo = $iblockInfo;
42 $this->setAutoloadDetailUrl(false);
43 }
44
45 public function getEntityById(int $id): ?BaseIblockElementEntity
46 {
47 if ($id <= 0)
48 {
49 throw new \OutOfRangeException($id);
50 }
51
52 $entities = $this->getEntitiesBy([
53 'filter' => [
54 '=ID' => $id,
55 ],
56 ]);
57
58 return reset($entities) ?: null;
59 }
60
61 public function getEntitiesBy($params): array
62 {
63 $entities = [];
64
65 foreach ($this->getList((array)$params) as $item)
66 {
67 $entities[] = $this->createEntity($item);
68 }
69
70 return $entities;
71 }
72
73 public function save(BaseEntity ...$entities): Result
74 {
75 $result = new Result();
76
77 $savedIds = [];
78
79 foreach ($entities as $entity)
80 {
81 $entityId = $entity->getId();
82 if ($entityId !== null)
83 {
84 $res = $this->updateInternal($entityId, $entity->getChangedFields());
85
86 if ($res->isSuccess())
87 {
88 $savedIds[] = $entityId;
89 }
90 else
91 {
92 $result->addErrors($res->getErrors());
93 }
94 }
95 else
96 {
97 $res = $this->addInternal($entity->getFields());
98
99 if ($res->isSuccess())
100 {
101 $id = $res->getData()['ID'];
102 $entity->setId($id);
103 $savedIds[] = $id;
104 }
105 else
106 {
107 $result->addErrors($res->getErrors());
108 }
109 }
110 }
111
112 // re-initialize original fields from database after save (DETAIL_PICTURE, etc)
113 if (!empty($savedIds))
114 {
115 $fields = $this->getList([
116 'filter' => [
117 'ID' => $savedIds,
118 ],
119 ]);
120
121 foreach ($entities as $entity)
122 {
123 $entityFields = $fields[$entity->getId()] ?? null;
124 if (!is_array($entityFields))
125 {
126 AddMessage2Log('Cannot load product ' . $entity->getId(), 'catalog');
127 continue;
128 }
129 $entityFields = array_diff_key($entityFields, ['TYPE' => true]);
130
131 if ($entityFields)
132 {
133 $entity->initFields($entityFields);
134 }
135 }
136 }
137
138 return $result;
139 }
140
141 public function delete(BaseEntity ...$entities): Result
142 {
143 $result = new Result();
144
145 foreach ($entities as $entity)
146 {
147 if ($entityId = $entity->getId())
148 {
149 $res = $this->deleteInternal($entityId);
150
151 if (!$res->isSuccess())
152 {
153 $result->addErrors($res->getErrors());
154 }
155 }
156 }
157
158 return $result;
159 }
160
161 public function setAutoloadDetailUrl(bool $state): self
162 {
163 $this->allowedDetailUrl = $state;
164
165 return $this;
166 }
167
168 public function checkAutoloadDetailUrl(): bool
169 {
170 return $this->allowedDetailUrl;
171 }
172
173 public function setDetailUrlTemplate(?string $template): self
174 {
175 $this->detailUrlTemplate = $template;
176
177 $this->setAutoloadDetailUrl($template !== null);
178
179 return $this;
180 }
181
182 public function getDetailUrlTemplate(): ?string
183 {
184 return $this->detailUrlTemplate;
185 }
186
187 protected function getDefaultElementSelect(): array
188 {
189 $result = [
190 'ID',
191 'TIMESTAMP_X',
192 'MODIFIED_BY',
193 'DATE_CREATE',
194 'CREATED_BY',
195 'IBLOCK_ID',
196 'IBLOCK_SECTION_ID',
197 'ACTIVE',
198 'ACTIVE_FROM',
199 'ACTIVE_TO',
200 'SORT',
201 'NAME',
202 'PREVIEW_PICTURE',
203 'PREVIEW_TEXT',
204 'PREVIEW_TEXT_TYPE',
205 'DETAIL_PICTURE',
206 'DETAIL_TEXT',
207 'DETAIL_TEXT_TYPE',
208 'WF_STATUS_ID',
209 'WF_PARENT_ELEMENT_ID',
210 'WF_NEW',
211 'IN_SECTIONS',
212 'SHOW_COUNTER',
213 'SHOW_COUNTER_START',
214 'CODE',
215 'TAGS',
216 'XML_ID',
217 'TMP_ID',
218 ];
219 if ($this->checkAutoloadDetailUrl())
220 {
221 $result[] = 'DETAIL_PAGE_URL';
222 }
223
224 return $result;
225 }
226
227 protected function getList(array $params): array
228 {
229 $filter = $params['filter'] ?? [];
230 $order = $params['order'] ?? [];
231 $nav = $params['nav'] ?? false;
232
233 $iblockElements = [];
234 $listIds = [];
235
236 $iterator = \CIBlockElement::GetList(
237 $order,
238 array_merge(
239 $filter,
240 $this->getAdditionalFilter(),
242 ),
243 false,
244 $nav,
245 [
246 'ID',
247 'IBLOCK_ID',
248 ],
249 );
250 while ($row = $iterator->fetch())
251 {
252 $id = (int)$row['ID'];
253 $iblockElements[$id] = $row;
254 $listIds[] = $id;
255 }
256 unset($iterator);
257
258 if (empty($iblockElements))
259 {
260 return [];
261 }
262
263 $elementSelect = $this->getDefaultElementSelect();
264 $detailUrlTemplate = $this->checkAutoloadDetailUrl() ? $this->getDetailUrlTemplate() : null;
265 $specificFields = [
266 'QUANTITY_TRACE' => 'QUANTITY_TRACE_ORIG',
267 'CAN_BUY_ZERO' => 'CAN_BUY_ZERO_ORIG',
268 'SUBSCRIBE' => 'SUBSCRIBE_ORIG',
269 ];
270 $productSelect = array_merge(['*', 'UF_*'], array_values($specificFields));
271
272 foreach (array_chunk($listIds, CATALOG_PAGE_SIZE) as $pageIds)
273 {
274 $elementsIterator = \CIBlockElement::GetList(
275 [],
276 [
277 'ID' => $pageIds,
278 'CHECK_PERMISSIONS' => 'N',
279 'SHOW_NEW' => 'Y',
280 ],
281 false,
282 false,
283 $elementSelect,
284 );
285 if ($detailUrlTemplate)
286 {
287 $elementsIterator->SetUrlTemplates($detailUrlTemplate);
288 }
289 while ($element = $elementsIterator->getNext())
290 {
291 $id = (int)$element['ID'];
292 $iblockElements[$id] += $this->replaceRawFromTilda($element);
293 }
294 unset($elementsIterator);
295
296 $productIterator = ProductTable::getList([
297 'select' => $productSelect,
298 'filter' => [
299 '@ID' => $pageIds,
300 ],
301 ]);
302 while ($product = $productIterator->fetch())
303 {
304 $id = (int)$product['ID'];
305 unset($product['ID']);
306 foreach ($specificFields as $field => $originalField)
307 {
308 $product[$field] = $product[$originalField];
309 unset($product[$originalField]);
310 }
311 $iblockElements[$id] += $product;
312 }
313 unset($productIterator);
314 }
315
316 return $iblockElements;
317 }
318
319 protected function getAdditionalFilter(): array
320 {
321 return [
322 'CHECK_PERMISSIONS' => 'N',
323 'MIN_PERMISSION' => 'R',
324 ];
325 }
326
327 protected function getAdditionalProductFilter(): array
328 {
329 return [];
330 }
331
332 protected function createEntity(array $fields = []): BaseIblockElementEntity
333 {
334 $entity = $this->makeEntity($fields);
335
336 $entity->initFields($fields);
337
338 return $entity;
339 }
340
341 abstract protected function makeEntity(array $fields = []): BaseIblockElementEntity;
342
343 protected function addInternal(array $fields): Result
344 {
345 $result = new Result();
346
347 $elementFields = $this->prepareElementFields($fields);
348
349 if (!empty($elementFields))
350 {
351 $element = new \CIBlockElement();
352 $id = $element->add($elementFields);
353
354 if ($id)
355 {
356 $result->setData(['ID' => $id]);
357 }
358 else
359 {
360 $result->addError(new Error($element->LAST_ERROR));
361 }
362 }
363
364 if ($result->isSuccess())
365 {
366 $productFields = $this->prepareProductFields($fields);
367
368 if (!empty($productFields))
369 {
370 $productFields['ID'] = $result->getData()['ID'];
371 $res = Product::add([
372 'fields' => $productFields,
373 'external_fields' => [
374 'IBLOCK_ID' => $elementFields['IBLOCK_ID'],
375 ],
376 ]);
377
378 if (!$res->isSuccess())
379 {
380 $result->addErrors($res->getErrors());
381 }
382 }
383 }
384
385 return $result;
386 }
387
388 protected function updateInternal(int $id, array $fields): Result
389 {
390 $result = new Result();
391
392 $elementFields = $this->prepareElementFields($fields);
393
394 if (!empty($elementFields))
395 {
396 $element = new \CIBlockElement();
397 $res = $element->update($id, $elementFields);
398
399 if (!$res)
400 {
401 $result->addError(new Error($element->LAST_ERROR));
402 }
403 }
404
405 if ($result->isSuccess())
406 {
407 $productFields = $this->prepareProductFields($fields);
408
409 if (!empty($productFields))
410 {
411 $res = Product::update($id, $productFields);
412
413 if (!$res->isSuccess())
414 {
415 $result->addErrors($res->getErrors());
416 }
417 }
418 }
419
420 return $result;
421 }
422
423 protected function deleteInternal(int $id): Result
424 {
425 $result = new Result();
426
427 $res = \CIBlockElement::delete($id);
428
429 if ($res)
430 {
431 $res = Product::delete($id);
432
433 if (!$res->isSuccess())
434 {
435 $result->addErrors($res->getErrors());
436 }
437 }
438 else
439 {
440 global $APPLICATION;
441 $exception = $APPLICATION->GetException();
442
443 if ($exception && $exception->GetString())
444 {
445 $errorMessage = $exception->GetString();
446 }
447 else
448 {
449 $errorMessage = "Delete operation for entity with id {$id} failed.";
450 }
451
452 $result->addError(new Error($errorMessage));
453 }
454
455 return $result;
456 }
457
458 protected function prepareElementFields(array $fields): array
459 {
460 if (array_key_exists('ACTIVE_FROM', $fields) && $fields['ACTIVE_FROM'] === null)
461 {
462 $fields['ACTIVE_FROM'] = false;
463 }
464
465 if (array_key_exists('ACTIVE_TO', $fields) && $fields['ACTIVE_TO'] === null)
466 {
467 $fields['ACTIVE_TO'] = false;
468 }
469
470 if (!array_key_exists('MODIFIED_BY', $fields))
471 {
472 global $USER;
473 if (isset($USER) && $USER instanceof \CUser)
474 {
475 $fields['MODIFIED_BY'] = $USER->getID();
476 }
477 }
478
479 return array_intersect_key($fields, ElementTable::getMap());
480 }
481
482 protected function prepareProductFields(array $fields): array
483 {
484 $catalogFields = array_intersect_key(
485 $fields,
486 array_fill_keys(
488 true
489 )
490 );
491
492 if (isset($catalogFields['TIMESTAMP_X']))
493 {
494 $catalogFields['TIMESTAMP_X'] = new DateTime($catalogFields['TIMESTAMP_X']);
495 }
496
497 if (isset($catalogFields['TYPE']))
498 {
499 $catalogFields['TYPE'] = (int)$catalogFields['TYPE'];
500 }
501
502 return $catalogFields;
503 }
504
505 private function replaceRawFromTilda(array $element): array
506 {
507 $newElement = [];
508
509 foreach ($element as $key => $value)
510 {
511 $tildaKey = "~{$key}";
512 if (isset($element[$tildaKey]))
513 {
514 $newElement[$key] = $element[$tildaKey];
515 }
516 }
517
518 return $newElement;
519 }
520}
static getTabletFieldNames(int $fields=self::FIELDS_MAIN)
Definition entity.php:435
__construct(BaseIblockElementFactory $factory, IblockInfo $iblockInfo)
static getList(array $parameters=array())