1C-Bitrix 25.700.0
Загрузка...
Поиск...
Не найдено
product.php
См. документацию.
1<?php
2
3namespace Bitrix\Catalog\Controller;
4
5use Bitrix\Catalog\Access\ActionDictionary;
6use Bitrix\Catalog\Config\State;
7use Bitrix\Catalog\Controller\Product\SkuDeferredCalculations;
8use Bitrix\Catalog\Model\Event;
9use Bitrix\Catalog\ProductTable;
10use Bitrix\Catalog\v2;
11use Bitrix\Iblock;
12use Bitrix\Main\Application;
13use Bitrix\Main\DB\SqlQueryException;
14use Bitrix\Main\Engine;
15use Bitrix\Main\Engine\Response\DataType\Page;
16use Bitrix\Main\Error;
17use Bitrix\Main\ORM;
18use Bitrix\Main\ORM\Data\DataManager;
19use Bitrix\Main\Result;
20use Bitrix\Main\Engine\ActionFilter\Scope;
21use Bitrix\Main\UI\PageNavigation;
22use Bitrix\Rest\Event\EventBindInterface;
23use Bitrix\Rest\RestException;
24
25class Product extends Controller implements EventBindInterface
26{
28
30
34 public function configureActions()
35 {
36 return [
37 'addProperty' => [
38 '+prefilters' => [new Scope(Scope::AJAX)]
39 ],
40 'getSkuTreeProperties' => [
41 '+prefilters' => [new Scope(Scope::AJAX)]
42 ],
43 ];
44 }
45
50 {
51 $result = new Result();
52
53 if ($action->getName() === 'add')
54 {
56 }
57 else if ($action->getName() === 'update')
58 {
60 }
61 else if ($action->getName() === 'getfieldsbyfilter')
62 {
64 }
65
66 if (!$result->isSuccess())
67 {
68 $this->addErrors($result->getErrors());
69
70 return null;
71 }
72
73 if ($this->isActionWithDefferedCalculation($action))
74 {
76 }
77
78 return parent::processBeforeAction($action);
79 }
80
90 {
91 if ($this->isActionWithDefferedCalculation($action))
92 {
94 }
95
96 return parent::processAfterAction($action, $result);
97 }
98
106 {
107 $arguments = $action->getArguments();
108
109 $fields = $arguments['fields'];
110 $productId = $arguments['id'];
111
112 $result = $this->exists($productId);
113 if (!$result->isSuccess())
114 {
115 return $result;
116 }
117
118 $element = $result->getData();
119
120 $iblockIdOrigin = $fields['iblockId'] ?? null;
121 if ($iblockIdOrigin !== null)
122 {
123 $iblockIdOrigin = (int)$iblockIdOrigin;
124 }
125
126 if ($iblockIdOrigin && $iblockIdOrigin !== $element['IBLOCK_ID'])
127 {
128 $result->addError(
129 new Error(
130 sprintf(
131 'Product - %d is not exists in catalog - %d', $productId , $iblockIdOrigin
132 )
133 )
134 );
135 }
136
137 if (!isset($fields['iblockId']))
138 {
139 $arguments['fields']['iblockId'] = $element['IBLOCK_ID'];
140 $action->setArguments($arguments);
141 }
142
143 return $result;
144 }
145
147 {
148 return new Result();
149 }
150
152 {
153 $result = new Result();
154 $arguments = $action->getArguments();
155
156 $filter = $arguments['filter'] ?? [];
157 if (!is_array($filter))
158 {
159 $result->addError(new Error('Incorrect filter format'));
160
161 return $result;
162 }
163 $filter['productType'] = static::TYPE;
164 $arguments['filter'] = $filter;
165 $action->setArguments($arguments);
166
167 return $result;
168 }
169
170 //region Actions
171 public function getFieldsByFilterAction($filter): ?array
172 {
174 $view = $this->getViewManager()
175 ->getView($this);
176 $r = $view->getFieldsByFilter($filter);
177
178 if(!$r->isSuccess())
179 {
180 $this->addErrors($r->getErrors());
181 return null;
182 }
183 else
184 {
185 return [$this->getServiceItemName() =>$view->prepareFieldInfos(
186 $r->getData()
187 )];
188 }
189 }
190
191 private static function perfGetList(array $select, array $filter, array $order, $pageNavigation = null): array
192 {
193 $count = null;
194 $rawRows = [];
195 $elementIds = [];
196
197 $iterator = \CIBlockElement::GetList(
198 $order,
199 $filter,
200 false,
201 $pageNavigation ?? false,
202 array('ID', 'IBLOCK_ID')
203 );
204 while($row = $iterator->Fetch())
205 {
206 $rawRows[$row['ID']] = $row;
207 $elementIds[] = $row['ID'];
208 }
209 if ($pageNavigation)
210 {
211 $count = (int)$iterator->NavRecordCount;
212 }
213 unset($row, $iterator);
214
215 $loadSections =
216 in_array('IBLOCK_SECTION', $select, true)
217 || in_array('*', $select, true)
218 ;
219
220 foreach (array_chunk($elementIds, \IRestService::LIST_LIMIT) as $pageIds)
221 {
222 $elementFilter = [
223 'IBLOCK_ID' => $filter['IBLOCK_ID'],
224 'ID' => $pageIds,
225 ];
226 $iterator = \CIBlockElement::GetList([], $elementFilter, false, false, $select);
227 while ($row = $iterator->Fetch())
228 {
229 $rawRows[$row['ID']] += $row;
230 }
231 unset($row, $iterator);
232
233 if ($loadSections)
234 {
235 self::attachIblockSections($rawRows);
236 }
237 }
238
239 return [
240 'ROWS' => $rawRows,
241 'COUNT' => $count,
242 ];
243 }
244
253 public function listAction(
254 PageNavigation $pageNavigation,
255 array $select = [],
256 array $filter = [],
257 array $order = [],
258 bool $__calculateTotalCount = true
259 ): ?Page
260 {
261 $r = $this->checkPermissionIBlockElementList($filter['IBLOCK_ID']);
262 if ($r->isSuccess())
263 {
264 $select = empty($select)? array_merge(['*'], $this->getAllowedFieldsProduct()):$select;
265 $order = empty($order)? ['ID'=>'ASC']:$order;
266
267 $groupFields = $this->splitFieldsByEntity(
268 array_flip($select)
269 );
270 $allProperties = isset($groupFields['elementFields']['PROPERTY_*']);
271 if ($allProperties)
272 {
273 unset($groupFields['elementFields']['PROPERTY_*']);
274 }
275
276 $productFields = array_keys($groupFields['productFields']);
277 $elementFields = array_keys($groupFields['elementFields']);
278 $propertyFields = $groupFields['propertyFields'];
279
281 $propertyIds = array_keys($propertyFields);
282
283 $items = self::perfGetList(
284 array_merge($productFields, $elementFields),
285 $filter,
286 $order,
287 self::getNavData($pageNavigation->getOffset())
288 );
289 $list = $items['ROWS'];
290 $count = $items['COUNT'];
291 unset($items);
292
293 if (empty($list))
294 {
295 return new Page(
296 $this->getServiceListName(),
297 [],
298 0
299 );
300 }
301
302 if ($allProperties || !empty($propertyIds))
303 {
304 self::attachPropertyValues($list, (int)$filter['IBLOCK_ID'], $propertyIds);
305 }
306
307 $totalCount = 0;
308 if ($__calculateTotalCount)
309 {
310 $totalCount = $count ?? $this->getCount($filter);
311 }
312
313 return new Page(
314 $this->getServiceListName(),
315 array_values($list),
317 );
318 }
319 else
320 {
321 $this->addErrors($r->getErrors());
322
323 return null;
324 }
325 }
326
327 public function getAction($id)
328 {
329 $id = (int)$id;
330 $result = $this->exists($id);
331 if (!$result->isSuccess())
332 {
333 $this->addErrors($result->getErrors());
334
335 return null;
336 }
337
338 $element = $result->getData();
339 $result = $this->checkPermissionIBlockElementGet($element['IBLOCK_ID'], $element['ID']);
340 if (!$result->isSuccess())
341 {
342 $this->addErrors($result->getErrors());
343
344 return null;
345 }
346
347 return [
348 $this->getServiceItemName() => $this->get($id),
349 ];
350 }
351
352 public function addAction(array $fields): ?array
353 {
354 $result = $this->checkPermissionAdd($fields['IBLOCK_ID']);
355 if (!$result->isSuccess())
356 {
357 $this->addErrors($result->getErrors());
358
359 return null;
360 }
361
362 if (isset($fields['IBLOCK_SECTION_ID']) && (int)$fields['IBLOCK_SECTION_ID'] > 0)
363 {
365 $fields['IBLOCK_ID'],
366 $fields['IBLOCK_SECTION_ID']
367 );
368
369 if (!$result->isSuccess())
370 {
371 $this->addErrors($result->getErrors());
372
373 return null;
374 }
375 }
376
377 $result = $this->addValidate($fields);
378 if (!$result->isSuccess())
379 {
380 $this->addErrors($result->getErrors());
381
382 return null;
383 }
384
386 if ($fields === null)
387 {
388 return null;
389 }
390
391 $groupFields = $this->splitFieldsByEntity($fields);
392
393 $productFields = $groupFields['productFields'];
394 $propertyFields = $groupFields['propertyFields'];
395 $elementFields = $groupFields['elementFields'];
396
398 $propertyFields = $this->verifyPropertyFields($fields['IBLOCK_ID'], $propertyFields);
400 $elementFieldsAdd =
401 !empty($propertyFields)
402 ? array_merge($elementFields, ['PROPERTY_VALUES' => $propertyFields])
403 : $elementFields
404 ;
405
406 $productService = new v2\Internal\ProductInternalService(true);
407
408 $conn = Application::getConnection();
409 $conn->startTransaction();
410 try
411 {
412 $result = $productService->add(array_merge($productFields, $elementFieldsAdd));
413 }
414 catch (SqlQueryException)
415 {
416 $result = new Result();
417 $result->addError(new Error('Internal error adding product. Try adding again.'));
418 }
419
420 if (!$result->isSuccess())
421 {
422 $conn->rollbackTransaction();
423 $this->addErrors($result->getErrors());
424
425 return null;
426 }
427 $conn->commitTransaction();
428
429 $id = $result->getData()['ID'];
430
431 return [
432 'ELEMENT' => $this->get($id),
433 ];
434 }
435
436 public function updateAction(int $id, array $fields): ?array
437 {
438 $result = $this->exists($id);
439 if (!$result->isSuccess())
440 {
441 $this->addErrors($result->getErrors());
442
443 return null;
444 }
445
446 $element = $result->getData();
447 $fields['IBLOCK_ID'] ??= $element['IBLOCK_ID'];
448
449 $result = $this->checkPermissionUpdate($element['IBLOCK_ID'], $element['ID']);
450 if (!$result->isSuccess())
451 {
452 $this->addErrors($result->getErrors());
453
454 return null;
455 }
456
457 $sectionId = (int)($fields['IBLOCK_SECTION_ID'] ?? null);
458 if ($sectionId > 0)
459 {
461 $element['IBLOCK_ID'],
462 $sectionId
463 );
464 if (!$result->isSuccess())
465 {
466 $this->addErrors($result->getErrors());
467
468 return null;
469 }
470 }
471
473 if ($fields === null)
474 {
475 return null;
476 }
477
478 $groupFields = $this->splitFieldsByEntity($fields);
479
480 $productFields = $groupFields['productFields'];
481 $propertyFields = $groupFields['propertyFields'];
482 $elementFields = $groupFields['elementFields'];
483
485 $propertyFields = $this->verifyPropertyFields((int)$fields['IBLOCK_ID'], $propertyFields);
487
490
491 $elementFieldsUpdate =
492 !empty($propertyFields)
493 ? array_merge(
494 $elementFields,
495 ['PROPERTY_VALUES' => $propertyFields]
496 )
497 : $elementFields
498 ;
499
500 if (!empty($elementFieldsUpdate))
501 {
502 $result = $this->updateValidate(
503 $elementFieldsUpdate + ['ID' => $id]
504 );
505 if (!$result->isSuccess())
506 {
507 $this->addErrors($result->getErrors());
508
509 return null;
510 }
511 }
512
513 if (
514 !empty($productFields)
515 || !empty($elementFieldsUpdate)
516 )
517 {
518 $productService = new v2\Internal\ProductInternalService(true);
519
520 $conn = Application::getConnection();
521 $conn->startTransaction();
522 try
523 {
524 $result = $productService->update(
525 $id,
526 array_merge($productFields, $elementFieldsUpdate)
527 );
528 }
529 catch (SqlQueryException)
530 {
531 $result = new Result();
532 $result->addError(new Error('Internal error updating product. Try updating again.'));
533 }
534
535 if (!$result->isSuccess())
536 {
537 $conn->rollbackTransaction();
538 $this->addErrors($result->getErrors());
539
540 return null;
541 }
542 $conn->commitTransaction();
543 }
544
545 return [
546 'ELEMENT' => $this->get($id),
547 ];
548 }
549
550 public function deleteAction(int $id): ?bool
551 {
552 $result = $this->exists($id);
553 if (!$result->isSuccess())
554 {
555 $this->addErrors($result->getErrors());
556
557 return null;
558 }
559 $element = $result->getData();
560 $result = $this->checkPermissionDelete($element['IBLOCK_ID'], $element['ID']);
561
562 if (!$result->isSuccess())
563 {
564 $this->addErrors($result->getErrors());
565
566 return null;
567 }
568
569 $conn = Application::getConnection();
570 $conn->startTransaction();
571 try
572 {
573 if (!\CIBlockElement::Delete($id))
574 {
575 $ex = self::getApplication()->GetException();
576 if ($ex)
577 {
578 $result->addError(new Error($ex->GetString(), $ex->GetId()));
579 }
580 else
581 {
582 $result->addError(new Error('delete iBlockElement error'));
583 }
584 }
585 }
586 catch (SqlQueryException)
587 {
588 $result = new Result();
589 $result->addError(new Error('Internal error deleting product. Try deleting again.'));
590 }
591
592 if ($result->isSuccess())
593 {
594 $conn->commitTransaction();
595
596 return true;
597 }
598 else
599 {
600 $conn->rollbackTransaction();
601 $this->addErrors($result->getErrors());
602
603 return null;
604 }
605 }
606
608 {
609 $productId = (int)($fields['PRODUCT_ID'] ?? null);
610 $fieldName = $fields['FIELD_NAME'];
611 $id = $fields['FILE_ID'];
612 $file = [];
613
614 $result = $this->exists($productId);
615 if (!$result->isSuccess())
616 {
617 $this->addErrors($result->getErrors());
618
619 return null;
620 }
621
622 $element = $result->getData();
623
624 if (
625 $this->checkFieldsDownload([
626 'NAME' => $fieldName,
627 'IBLOCK_ID' => $element['IBLOCK_ID'],
628 ])
629 )
630 {
631 $files = [];
632 $iterator = \CIBlockElement::GetList(
633 [],
634 [
635 'IBLOCK_ID' => $element['IBLOCK_ID'],
636 '=ID' => $element['ID'],
637 'CHECK_PERMISSIONS' => 'N',
638 ],
639 false,
640 false,
641 [
642 'ID',
643 'IBLOCK_ID',
644 $fieldName,
645 ]
646 );
647 while ($res = $iterator->GetNext())
648 {
649 if (isset($res[$fieldName]))
650 {
651 $files[] = (int)$res[$fieldName];
652 }
653 elseif (isset($res[$fieldName."_VALUE"]))
654 {
655 if (is_array($res[$fieldName."_VALUE"]))
656 {
657 $list = $res[$fieldName . '_VALUE'];
658 \Bitrix\Main\Type\Collection::normalizeArrayValuesByInt($list);
659 if (!empty($list))
660 {
661 $files = array_merge($files, $list);
662 }
663 unset($list);
664 }
665 else
666 {
667 $files[] = (int)$res[$fieldName."_VALUE"];
668 }
669 }
670 }
671 unset($res, $iterator);
672
673 if (!in_array($id, $files))
674 {
675 $result->addError(new Error('Product file wrong'));
676 }
677 else
678 {
679 $file = \CFile::GetFileArray($id);
680 if (!is_array($file))
681 {
682 $result->addError(new Error('Product is empty'));
683 }
684 }
685 }
686 else
687 {
688 $result->addError(new Error('Name file field is not available'));
689 }
690
691 if ($result->isSuccess())
692 {
693 return \Bitrix\Main\Engine\Response\BFile::createByFileId($file['ID']);
694 }
695 else
696 {
697 $this->addErrors($result->getErrors());
698
699 return null;
700 }
701 }
702 //endregion Actions
703
704 private function getCount(array $filter): \Closure
705 {
706 return function() use ($filter)
707 {
708 return (int)\CIBlockElement::GetList([], $filter, []);
709 };
710 }
711
712 protected function getEntityTable()
713 {
714 return \Bitrix\Catalog\Model\Product::getTabletClassName();
715 }
716
717 protected function splitFieldsByEntity($fields): array
718 {
719 $productFields = [];
720 $elementFields = [];
721 $propertyFields = [];
722
723 foreach($fields as $name=>$value)
724 {
725 if(in_array($name, $this->getAllowedFieldsProduct()))
726 {
727 $productFields[$name] = $value;
728 }
729 else
730 {
731 if (preg_match('/^(PROPERTY_\d+)$/', $name))
732 {
733 $propertyFields[$name] = $value;
734 }
735 else
736 {
737 $elementFields[$name] = $value;
738 }
739 }
740 }
741
742 return [
743 'productFields'=>$productFields,
744 'propertyFields'=>$propertyFields,
745 'elementFields'=>$elementFields
746 ];
747 }
748
750 {
752
753 if (State::isUsedInventoryManagement())
754 {
755 unset($result['QUANTITY_TRACE']);
756 }
757
758 return $result;
759 }
760
761 private function verifyPropertyFields(int $iblockId, array $fields): array
762 {
763 $singleProperties = [];
765 'select' => [
766 'ID',
767 'PROPERTY_TYPE',
768 'USER_TYPE',
769 ],
770 'filter' => [
771 '=IBLOCK_ID' => $iblockId,
772 '@PROPERTY_TYPE' => [
775 ],
776 '=ACTIVE' => 'Y',
777 '=MULTIPLE' => 'N',
778 ],
779 'order' => [
780 'ID' => 'ASC',
781 ],
782 'cache' => [
783 'ttl' => 86400,
784 ]
785 ]);
786 while ($row = $iterator->Fetch())
787 {
788 if ((string)$row['USER_TYPE'] !== '')
789 {
790 continue;
791 }
792
793 $singleProperties['PROPERTY_' . $row['ID']] = true;
794 }
795 unset(
796 $row,
797 $iterator,
798 );
799
800 $result = [];
801
802 foreach ($fields as $name => $value)
803 {
804 if (
805 isset($singleProperties[$name])
806 && isset($value['VALUE'])
807 && is_array($value['VALUE'])
808 )
809 {
810 continue;
811 }
812
813 $result[$name] = $value;
814 }
815
816 return $result;
817 }
818
819 protected function preparePropertyFields($fields)
820 {
821 $result = [];
822 $matches = [];
823
824 foreach($fields as $name=>$value)
825 {
826 if (preg_match('/^(PROPERTY_)(\d+)$/', $name, $matches))
827 {
828 $result[$matches[2]] = $value;
829 }
830 }
831 return $result;
832 }
833
835 {
836 $result = [];
837
838 if(count($fields)>0)
839 {
840 foreach ($fields as $propertyId=>$value)
841 {
842 $property = [];
843 // single
844 if(isset($value['VALUE']))
845 {
846 if(isset($value['VALUE_ID']))
847 {
848 //update
849 $valueId=$value['VALUE_ID'];
850 unset($value['VALUE_ID']);
851 $property[$valueId]=$value;
852
853 }
854 else
855 {
856 //replace
857 $property[]=$value;
858 }
859 }
860 // multi
861 else
862 {
863 if(is_array($value) && count($value)>0)
864 {
865 foreach ($value as $item)
866 {
867 if(isset($item['VALUE_ID']))
868 {
869 //update
870 $valueId = $item['VALUE_ID'];
871 unset($item['VALUE_ID']);
872 $property[$valueId]=$item;
873 }
874 else
875 {
876 //replace
877 $property[]=$item;
878 }
879 }
880 }
881 }
882
883 if(count($property)>0)
884 {
885 $result[$propertyId]=$property;
886 }
887 }
888 }
889 return $result;
890 }
891
892 protected function fillPropertyFieldsDefaultPropertyValues($id, $iblockId, $propertyValues)
893 {
894 $fields = $propertyValues;
895
896 if ($id > 0 && $iblockId > 0 && !empty($propertyValues))
897 {
898 $r = \CIBlockElement::GetProperty(
899 $iblockId,
900 $id,
901 'SORT',
902 'ASC',
903 [
904 'CHECK_PERMISSIONS' => 'N',
905 'EMPTY' => 'N',
906 ]
907 );
908 while ($property = $r->Fetch())
909 {
910 if (
911 $property['PROPERTY_TYPE'] !== Iblock\PropertyTable::TYPE_FILE
912 && !array_key_exists($property['ID'], $propertyValues)
913 )
914 {
915 $fields[$property['ID']] ??= [];
916
917 $fields[$property['ID']][] = [
918 'VALUE_ID' => $property['PROPERTY_VALUE_ID'],
919 'VALUE' => $property['VALUE'],
920 'DESCRIPTION' => $property['DESCRIPTION'],
921 ];
922 }
923 }
924 unset($property, $r);
925 }
926
927 return $fields;
928 }
929
930 protected function exists($id)
931 {
932 $result = new Result();
933
934 $row = null;
935 $id = (int)$id;
936 if ($id > 0)
937 {
939 'select' => [
940 'ID',
941 'IBLOCK_ID',
942 ],
943 'filter' => [
944 '=ID' => $id,
945 ],
946 ]);
947 }
948 if ($row === null)
949 {
950 $result->addError($this->getErrorEntityNotExists());
951
952 return $result;
953 }
954
955 $row['ID'] = (int)$row['ID'];
956 $row['IBLOCK_ID'] = (int)$row['IBLOCK_ID'];
957 $result->setData($row);
958
959 return $result;
960 }
961
962 protected function get($id)
963 {
964 $row = \CIBlockElement::getList(
965 [],
966 ['ID' => $id],
967 false,
968 false,
969 [
970 '*',
971 ...$this->getAllowedFieldsProduct()
972 ]
973 )->fetch();
974
975 if (!$row)
976 {
977 return [];
978 }
979
980 $result = [
981 $row['ID'] => $row,
982 ];
983
984 self::attachIblockSections($result);
985 self::attachPropertyValues($result, (int)$row['IBLOCK_ID']);
986
987 return $result[$row['ID']];
988 }
989
990 protected function addValidate($fields)
991 {
992 return $this->checkFields($fields);
993 }
994
995 protected function updateValidate($fields)
996 {
997 return $this->checkFields($fields);
998 }
999
1000 protected function checkFields($fields)
1001 {
1002 $r = new Result();
1003
1004 if (isset($fields['SECTION_ID']))
1005 {
1006 $section = \CIBlockSection::GetByID($fields['SECTION_ID'])->Fetch();
1007 if (!isset($section['ID']))
1008 {
1009 $r->addError(new Error('Section is not exists'));
1010 }
1011 }
1012 if (isset($fields['MODIFIED_BY']))
1013 {
1014 $user = \CUser::GetByID($fields['MODIFIED_BY'])->Fetch();
1015 if (!isset($user['ID']))
1016 {
1017 $r->addError(new Error('User modifiedBy is not exists'));
1018 }
1019 }
1020 if (isset($fields['CREATED_BY']))
1021 {
1022 $user = \CUser::GetByID($fields['CREATED_BY'])->Fetch();
1023 if (!isset($user['ID']))
1024 {
1025 $r->addError(new Error('User createdBy is not exists'));
1026 }
1027 }
1028 if (isset($fields['PURCHASING_CURRENCY']))
1029 {
1030 $currency = \CCurrency::GetByID($fields['PURCHASING_CURRENCY']);
1031 if (!isset($currency['CURRENCY']))
1032 {
1033 $r->addError(new Error('Currency purchasingCurrency is not exists'));
1034 }
1035 }
1036 if (isset($fields['VAT_ID']))
1037 {
1038 $user = \CCatalogVat::GetByID($fields['VAT_ID'])->Fetch();
1039 if (!isset($user['ID']))
1040 {
1041 $r->addError(new Error('VAT vatId is not exists'));
1042 }
1043 }
1044
1045 return $r;
1046 }
1047
1049 {
1050 $dateAlias = [
1051 'DATE_ACTIVE_FROM' => 'ACTIVE_FROM',
1052 'DATE_ACTIVE_TO' => 'ACTIVE_TO',
1053 ];
1054
1055 foreach ($dateAlias as $alias => $name)
1056 {
1057 if (!isset($fields[$name]) && isset($fields[$alias]))
1058 {
1059 $fields[$name] = $fields[$alias];
1060 unset(
1061 $fields[$alias],
1062 );
1063 }
1064 }
1065
1066 return $fields;
1067 }
1068
1070 {
1071 return $this->prepareDateAliases($fields);
1072 }
1073
1075 {
1076 return $this->prepareDateAliases($fields);
1077 }
1078
1079 protected static function attachIblockSections(array &$result): void
1080 {
1081 if (empty($result))
1082 {
1083 return;
1084 }
1085
1086 $listIds = array_keys($result);
1087 foreach ($listIds as $id)
1088 {
1089 $result[$id]['IBLOCK_SECTION'] = [];
1090 }
1091
1093 $filter->whereNull('ADDITIONAL_PROPERTY_ID');
1094 foreach (array_chunk($listIds, CATALOG_PAGE_SIZE) as $pageIds)
1095 {
1096 $filter->whereIn('IBLOCK_ELEMENT_ID', $pageIds);
1097 $iterator = Iblock\SectionElementTable::getList([
1098 'select' => [
1099 'IBLOCK_ELEMENT_ID',
1100 'IBLOCK_SECTION_ID',
1101 ],
1102 'filter' => $filter,
1103 ]);
1104 while ($row = $iterator->fetch())
1105 {
1106 $id = (int)$row['IBLOCK_ELEMENT_ID'];
1107 $result[$id]['IBLOCK_SECTION'][] = (int)$row['IBLOCK_SECTION_ID'];
1108 }
1109 unset(
1110 $row,
1111 $iterator,
1112 );
1113 }
1114 }
1115
1122 protected static function attachPropertyValues(array &$result, int $iblockId, array $propertyIds = []): void
1123 {
1124 if ($iblockId <= 0)
1125 {
1126 return;
1127 }
1128
1129 $propertyFilter = !empty($propertyIds) ? ['ID' => $propertyIds] : [];
1130
1131 $propertyValues = [];
1132 \CIBlockElement::getPropertyValuesArray(
1133 $propertyValues,
1134 $iblockId,
1135 ['ID' => array_keys($result)],
1136 $propertyFilter,
1137 ['USE_PROPERTY_ID' => 'Y']
1138 );
1139
1140 foreach ($result as $k => $v)
1141 {
1142 if (isset($propertyValues[$k]))
1143 {
1144 foreach ($propertyValues[$k] as $propId => $fields)
1145 {
1146 $value = null;
1147
1148 if (isset($fields['PROPERTY_VALUE_ID']))
1149 {
1150 if ($fields['PROPERTY_TYPE'] === Iblock\PropertyTable::TYPE_LIST)
1151 {
1152 if ($fields['MULTIPLE'] === 'Y')
1153 {
1154 if (is_array($fields['PROPERTY_VALUE_ID']))
1155 {
1156 foreach ($fields['PROPERTY_VALUE_ID'] as $i => $item)
1157 {
1158 $value[] = [
1159 'VALUE' => $fields['VALUE_ENUM_ID'][$i],
1160 'VALUE_ENUM' => $fields['VALUE_ENUM'][$i],
1161 'VALUE_ID' => $fields['PROPERTY_VALUE_ID'][$i],
1162 ];
1163 }
1164 }
1165 }
1166 else
1167 {
1168 $value = [
1169 'VALUE' => $fields['VALUE_ENUM_ID'],
1170 'VALUE_ENUM' => $fields['VALUE_ENUM'],
1171 'VALUE_ID' => $fields['PROPERTY_VALUE_ID']
1172 ];
1173 }
1174 }
1175 else
1176 {
1177 if ($fields['MULTIPLE'] === 'Y')
1178 {
1179 if (is_array($fields['PROPERTY_VALUE_ID']))
1180 {
1181 foreach ($fields['PROPERTY_VALUE_ID'] as $i => $item)
1182 {
1183 $value[] = [
1184 'VALUE' => $fields['VALUE'][$i],
1185 'VALUE_ID' => $fields['PROPERTY_VALUE_ID'][$i]
1186 ];
1187 }
1188 }
1189 }
1190 else
1191 {
1192 $value = [
1193 'VALUE' => $fields['VALUE'],
1194 'VALUE_ID' => $fields['PROPERTY_VALUE_ID']
1195 ];
1196 }
1197 }
1198 }
1199
1200 $result[$k]['PROPERTY_' . $propId] = $value;
1201 }
1202 }
1203 elseif (!empty($propertyIds))
1204 {
1208
1209 foreach ($propertyIds as $propId)
1210 {
1211 $result[$k]['PROPERTY_' . $propId] = null;
1212 }
1213 }
1214 }
1215 }
1216
1217 protected function checkPermissionEntity($name, $arguments=[])
1218 {
1219 $name = mb_strtolower($name); //for ajax mode
1220
1221 if($name == 'getfieldsbyfilter'
1222 || $name == 'download'
1223 )
1224 {
1225 $r = $this->checkReadPermissionEntity();
1226 }
1227 else
1228 {
1229 $r = parent::checkPermissionEntity($name);
1230 }
1231
1232 return $r;
1233 }
1234
1238 protected function getAllowedFieldsProduct(): array
1239 {
1240 $result = [
1241 'TYPE',
1242 'AVAILABLE',
1243 'BUNDLE',
1244 'QUANTITY',
1245 'QUANTITY_RESERVED',
1246 'QUANTITY_TRACE',
1247 'CAN_BUY_ZERO',
1248 'SUBSCRIBE',
1249 'VAT_ID',
1250 'VAT_INCLUDED',
1251 'BARCODE_MULTI',
1252 'WEIGHT',
1253 'LENGTH',
1254 'WIDTH',
1255 'HEIGHT',
1256 'MEASURE',
1257 'RECUR_SCHEME_LENGTH',
1258 'RECUR_SCHEME_TYPE',
1259 'TRIAL_PRICE_ID',
1260 'WITHOUT_ORDER',
1261 'QUANTITY_TRACE_RAW',
1262 'PAYMENT_TYPE',
1263 'SUBSCRIBE_RAW',
1264 'CAN_BUY_ZERO_RAW'
1265 ];
1266
1267 if ($this->accessController->check(ActionDictionary::ACTION_PRODUCT_PURCHASE_INFO_VIEW))
1268 {
1269 array_push($result, 'PURCHASING_PRICE', 'PURCHASING_CURRENCY');
1270 }
1271
1272 return $result;
1273 }
1274
1275 protected function checkFieldsDownload($fields)
1276 {
1277 $name = $fields['NAME'];
1278 $iblockId = $fields['IBLOCK_ID'];
1279
1280 if ($name === "DETAIL_PICTURE")
1281 {
1282 return true;
1283 }
1284 elseif ($name === "PREVIEW_PICTURE")
1285 {
1286 return true;
1287 }
1288 elseif ($name === "PICTURE")
1289 {
1290 return true;
1291 }
1292 elseif (!preg_match("/^PROPERTY_(.+)\$/", $name, $match))
1293 {
1294 return false;
1295 }
1296 else
1297 {
1298 $property = \CIBlockProperty::GetPropertyArray($match[1], $iblockId);
1299 if (is_array($property) && $property["PROPERTY_TYPE"] === Iblock\PropertyTable::TYPE_FILE)
1300 {
1301 return true;
1302 }
1303 }
1304 return false;
1305 }
1306
1308 {
1309 $result = $this->checkPermissionIBlockModify($fields['IBLOCK_ID']);
1310 if (!$result->isSuccess())
1311 {
1312 $this->addErrors($result->getErrors());
1313
1314 return null;
1315 }
1316
1317 $iblockProperty = new \CIBlockProperty();
1318
1319 $propertyFields = [
1320 'ACTIVE' => 'Y',
1321 'IBLOCK_ID' => $fields['IBLOCK_ID'],
1322 'NAME' => $fields['NAME'],
1323 'SORT' => $fields['SORT'] ?? 100,
1324 'CODE' => $fields['CODE'] ?? '',
1325 'MULTIPLE' => ($fields['MULTIPLE'] === 'Y') ? 'Y' : 'N',
1326 'IS_REQUIRED'=> ($fields['IS_REQUIRED'] === 'Y') ? 'Y' : 'N',
1327 'SECTION_PROPERTY'=> 'N',
1328 ];
1329
1330 $newId = (int)($iblockProperty->Add($propertyFields));
1331 if ($newId === 0)
1332 {
1333 $this->addError(new Error($iblockProperty->getLastError()));
1334
1335 return null;
1336 }
1337
1338 return [
1339 'ID' => $newId,
1340 'CONTROL_ID' => 'PROPERTY_' . $newId
1341 ];
1342 }
1343
1344 //region checkPermissionController
1345 protected function checkModifyPermissionEntity()
1346 {
1347 return $this->checkReadPermissionEntity();
1348 }
1349
1350 protected function checkReadPermissionEntity()
1351 {
1352 $r = new Result();
1353
1354 if (
1355 !$this->accessController->check(ActionDictionary::ACTION_CATALOG_READ)
1356 && !$this->accessController->check(ActionDictionary::ACTION_PRICE_EDIT)
1357 && !$this->accessController->check(ActionDictionary::ACTION_CATALOG_VIEW)
1358 )
1359 {
1360 $r->addError($this->getErrorReadAccessDenied());
1361 }
1362 return $r;
1363 }
1364 //endregion checkPermissionController
1365
1366 //region checkPermissionIBlock
1367 protected function existsIblock(int $iblockId): Result
1368 {
1369 $result = new Result();
1370
1371 $iblockName = \CIBlock::GetArrayByID($iblockId, 'NAME');
1372 if (empty($iblockName))
1373 {
1374 $result->addError(new Error('Iblock Not Found', 200040300000));
1375 }
1376
1377 return $result;
1378 }
1379
1380 protected function checkPermissionAdd(int $iblockId): Result
1381 {
1382 $result = new Result();
1383
1384 $result->addErrors(
1386 );
1387 $result->addErrors(
1389 );
1390
1391 return $result;
1392 }
1393
1395 {
1396 $result = new Result();
1397
1398 if (!$this->accessController->check(ActionDictionary::ACTION_PRODUCT_ADD))
1399 {
1400 $result->addError(new Error('Access Denied', 200040300040));
1401 }
1402
1403 return $result;
1404 }
1405
1407 {
1408 //return $this->checkPermissionIBlockElementList($iblockId);
1410 }
1411
1412 protected function checkPermissionUpdate(int $iblockId, int $elementId): Result
1413 {
1414 $result = new Result();
1415
1416 $result->addErrors(
1418 );
1419 $result->addErrors(
1421 );
1422
1423 return $result;
1424 }
1425
1427 {
1428 $result = new Result();
1429
1430 if (!$this->accessController->check(ActionDictionary::ACTION_PRODUCT_EDIT))
1431 {
1432 $result->addError(new Error('Access Denied', 200040300040));
1433 }
1434
1435 return $result;
1436 }
1437
1438 protected function checkPermissionIBlockElementUpdate(int $iblockId, int $elementId): Result
1439 {
1440 return $this->checkPermissionIBlockElementModify($iblockId, $elementId);
1441 }
1442
1444 {
1445 $iblockId = (int)$iblockId;
1446
1447 $r = $this->existsIblock($iblockId);
1448 if (!$r->isSuccess())
1449 {
1450 return $r;
1451 }
1452
1453 if (!\CIBlockRights::UserHasRightTo($iblockId, $iblockId, self::IBLOCK_EDIT))
1454 {
1455 $r->addError(new Error('Access Denied', 200040300040));
1456 }
1457
1458 return $r;
1459 }
1460
1461 protected function checkPermissionIBlockElementModify($iblockId, $elementId): Result
1462 {
1463 $iblockId = (int)$iblockId;
1464
1465 $r = $this->existsIblock($iblockId);
1466 if (!$r->isSuccess())
1467 {
1468 return $r;
1469 }
1470
1471 if ($elementId > 0)
1472 {
1473 $badBlock = !\CIBlockElementRights::UserHasRightTo($iblockId, $elementId, self::IBLOCK_ELEMENT_EDIT); //access edit
1474 }
1475 else
1476 {
1477 $badBlock = !\CIBlockRights::UserHasRightTo($iblockId, $iblockId, self::IBLOCK_ELEMENT_EDIT);
1478 }
1479
1480 if ($badBlock)
1481 {
1482 $r->addError(new Error('Access Denied', 200040300043));
1483 }
1484
1485 return $r;
1486 }
1487
1488 protected function checkPermissionDelete(int $iblockId, int $elementId): Result
1489 {
1490 $result = new Result();
1491
1492 $result->addErrors(
1494 );
1495 $result->addErrors(
1497 );
1498
1499 return $result;
1500 }
1501
1503 {
1504 $result = new Result();
1505
1506 if (!$this->accessController->check(ActionDictionary::ACTION_PRODUCT_DELETE))
1507 {
1508 $result->addError(new Error('Access Denied', 200040300040));
1509 }
1510
1511 return $result;
1512 }
1513
1514 protected function checkPermissionIBlockElementDelete(int $iblockId, int $elementId): Result
1515 {
1516 $r = $this->existsIblock($iblockId);
1517 if (!$r->isSuccess())
1518 {
1519 return $r;
1520 }
1521
1522 if (!\CIBlockElementRights::UserHasRightTo($iblockId, $elementId, self::IBLOCK_ELEMENT_DELETE)) //access delete
1523 {
1524 $r->addError(new Error('Access Denied', 200040300040));
1525 }
1526
1527 return $r;
1528 }
1529
1530 protected function checkPermissionIBlockElementGet(int $iblockId, int $elementId): Result
1531 {
1532 $r = $this->existsIblock($iblockId);
1533 if (!$r->isSuccess())
1534 {
1535 return $r;
1536 }
1537
1538 if (!\CIBlockElementRights::UserHasRightTo($iblockId, $elementId, self::IBLOCK_ELEMENT_READ)) //access read
1539 {
1540 $r->addError(new Error('Access Denied', 200040300040));
1541 }
1542
1543 return $r;
1544 }
1545
1547 {
1548 $iblockId = (int)$iblockId;
1549 $r = $this->existsIblock($iblockId);
1550 if (!$r->isSuccess())
1551 {
1552 return $r;
1553 }
1554
1555 if (!\CIBlockRights::UserHasRightTo($iblockId, $iblockId, self::IBLOCK_READ))
1556 {
1557 $r->addError(new Error('Access Denied', 200040300030));
1558 }
1559
1560 return $r;
1561 }
1562
1564 {
1565 $iblockId = (int)$iblockId;
1566 $r = $this->existsIblock($iblockId);
1567 if (!$r->isSuccess())
1568 {
1569 return $r;
1570 }
1571
1572 if (!\CIBlockSectionRights::UserHasRightTo(
1573 $iblockId,
1574 $iblockSectionId,
1575 self::IBLOCK_ELEMENT_SECTION_BIND
1576 )) //access update
1577 {
1578 $r->addError(new Error('Access Denied', 200040300050));
1579 }
1580
1581 return $r;
1582 }
1583
1584 protected function checkPermissionIBlockElementSectionBindUpdate(int $iblockId, $iblockSectionId): Result
1585 {
1586 return $this->checkPermissionIBlockElementSectionBindModify($iblockId, $iblockSectionId);
1587 }
1588
1589 //endregion
1590
1591 // rest-event region
1595 public static function getCallbackRestEvent(): array
1596 {
1597 return [self::class, 'processItemEvent'];
1598 }
1599
1600 public static function processItemEvent(array $params, array $handler): array
1601 {
1602 $id = null;
1603 $event = $params[0] ?? null;
1604
1605 if (!$event)
1606 {
1607 throw new RestException('event object not found trying to process event');
1608 }
1609
1610 if ($event instanceof \Bitrix\Main\Event) // update, add
1611 {
1612 $id = $event->getParameter('id');
1613 }
1614 else if($event instanceof \Bitrix\Main\ORM\Event) // delete
1615 {
1616 $item = $event->getParameter('id');
1617 $id = is_array($item) ? $item['ID']: $item;
1618 }
1619
1620 if (!$id)
1621 {
1622 throw new RestException('id not found trying to process event');
1623 }
1624
1625 $product = \Bitrix\Catalog\Model\Product::getCacheItem($id, true);
1626
1627 $type = $product['TYPE'] ?? null;
1628
1629 if (!$type)
1630 {
1631 throw new RestException('type is not specified trying to process event');
1632 }
1633
1634 return [
1635 'FIELDS' => [
1636 'ID' => $id,
1637 'TYPE' => $type
1638 ],
1639 ];
1640 }
1641
1642 protected static function getBindings(): array
1643 {
1644 $entity = (new static())->getEntity();
1645 $class = $entity->getNamespace() . $entity->getName();
1646 $model = \Bitrix\Catalog\Model\Product::class;
1647
1648 $updateEventName = v2\Event\Event::makeEventName(
1649 v2\Event\Event::ENTITY_PRODUCT,
1650 v2\Event\Event::METHOD_UPDATE,
1651 v2\Event\Event::STAGE_AFTER
1652 );
1653
1654 return [
1655 Event::makeEventName($model,DataManager::EVENT_ON_AFTER_ADD) => $entity->getModule().'.'.$entity->getName().'.on.add',
1656 $updateEventName => $entity->getModule().'.'.$entity->getName().'.on.update',
1657 Event::makeEventName($class,DataManager::EVENT_ON_DELETE) => $entity->getModule().'.'.$entity->getName().'.on.delete',
1658 ];
1659 }
1660 // endregion
1661}
$count
Определения admin_tab.php:4
$type
Определения options.php:106
const CATALOG_PAGE_SIZE
Определения include.php:111
if($strVal !='') $productFields
Определения options.php:1791
prepareFieldsForAdd(array $fields)
Определения product.php:1069
checkPermissionIBlockElementModify($iblockId, $elementId)
Определения product.php:1461
checkModifyPermissionEntity()
Определения product.php:1345
static getCallbackRestEvent()
Определения product.php:1595
splitFieldsByEntity($fields)
Определения product.php:717
listAction(PageNavigation $pageNavigation, array $select=[], array $filter=[], array $order=[], bool $__calculateTotalCount=true)
Определения product.php:253
checkPermissionCatalogProductUpdate()
Определения product.php:1426
checkReadPermissionEntity()
Определения product.php:1350
checkPermissionIBlockElementUpdate(int $iblockId, int $elementId)
Определения product.php:1438
static attachPropertyValues(array &$result, int $iblockId, array $propertyIds=[])
Определения product.php:1122
prepareFieldsForUpdate(array $fields)
Определения product.php:1074
processBeforeAdd(Engine\Action $action)
Определения product.php:146
checkPermissionIBlockElementSectionBindUpdate(int $iblockId, $iblockSectionId)
Определения product.php:1584
addValidate($fields)
Определения product.php:990
preparePropertyFieldsUpdate($fields)
Определения product.php:834
addAction(array $fields)
Определения product.php:352
static getBindings()
Определения product.php:1642
checkPermissionIBlockElementAdd(int $iblockId)
Определения product.php:1406
processBeforeAction(Engine\Action $action)
Определения product.php:49
checkPermissionIBlockModify($iblockId)
Определения product.php:1443
updateValidate($fields)
Определения product.php:995
processBeforeUpdate(Engine\Action $action)
Определения product.php:105
checkPermissionCatalogProductDelete()
Определения product.php:1502
downloadAction(array $fields)
Определения product.php:607
checkFieldsDownload($fields)
Определения product.php:1275
processAfterAction(Engine\Action $action, $result)
Определения product.php:89
deleteAction(int $id)
Определения product.php:550
checkPermissionIBlockElementList($iblockId)
Определения product.php:1546
updateAction(int $id, array $fields)
Определения product.php:436
preparePropertyFields($fields)
Определения product.php:819
processBeforeGetFieldsByFilter(Engine\Action $action)
Определения product.php:151
prepareDateAliases(array $fields)
Определения product.php:1048
static processItemEvent(array $params, array $handler)
Определения product.php:1600
fillPropertyFieldsDefaultPropertyValues($id, $iblockId, $propertyValues)
Определения product.php:892
checkPermissionUpdate(int $iblockId, int $elementId)
Определения product.php:1412
static attachIblockSections(array &$result)
Определения product.php:1079
checkPermissionIBlockElementGet(int $iblockId, int $elementId)
Определения product.php:1530
prepareProductFields(array $fields)
Определения product.php:749
existsIblock(int $iblockId)
Определения product.php:1367
checkFields($fields)
Определения product.php:1000
checkPermissionDelete(int $iblockId, int $elementId)
Определения product.php:1488
checkPermissionEntity($name, $arguments=[])
Определения product.php:1217
checkPermissionAdd(int $iblockId)
Определения product.php:1380
addPropertyAction($fields)
Определения product.php:1307
checkPermissionIBlockElementDelete(int $iblockId, int $elementId)
Определения product.php:1514
checkPermissionIBlockElementSectionBindModify($iblockId, $iblockSectionId)
Определения product.php:1563
checkPermissionCatalogProductAdd()
Определения product.php:1394
static getCacheItem($id, bool $load=false)
Определения entity.php:396
const TYPE_PRODUCT
Определения product.php:70
static makeEventName(string $entity, string $method, string $stage)
Определения Event.php:31
const TYPE_FILE
Определения propertytable.php:67
const TYPE_STRING
Определения propertytable.php:65
const TYPE_LIST
Определения propertytable.php:70
const TYPE_NUMBER
Определения propertytable.php:66
getCount()
Определения result.php:320
Определения error.php:15
$filter
Определения event.php:11
static getRow(array $parameters)
Определения datamanager.php:398
static getList(array $parameters=array())
Определения datamanager.php:431
static filter()
Определения query.php:906
static GetByID($ID)
Определения vat.php:110
static GetByID($currency)
Определения currency.php:453
const LIST_LIMIT
Определения rest.php:897
</td ></tr ></table ></td ></tr >< tr >< td class="bx-popup-label bx-width30"><?=GetMessage("PAGE_NEW_TAGS")?> array( $site)
Определения file_new.php:804
$res
Определения filter_act.php:7
$result
Определения get_property_values.php:14
$entity
$iblockId
Определения iblock_catalog_edit.php:30
$select
Определения iblock_catalog_list.php:194
$filter
Определения iblock_catalog_list.php:54
$name
Определения menu_edit.php:35
isActionWithDefferedCalculation(Action $action)
Определения skudeferredcalculations.php:17
exists($id)
Определения checkexists.php:30
Определения Event.php:3
Определения action.php:3
Определения aliases.php:54
$user
Определения mysql_to_pgsql.php:33
getErrors()
Определения errorableimplementation.php:34
$files
Определения mysql_to_pgsql.php:30
$order
Определения payment.php:8
$event
Определения prolog_after.php:141
if( $daysToExpire >=0 &&$daysToExpire< 60 elseif)( $daysToExpire< 0)
Определения prolog_main_admin.php:393
$i
Определения factura.php:643
</p ></td >< td valign=top style='border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 2.0pt 0cm 2.0pt;height:9.0pt'>< p class=Normal align=center style='margin:0cm;margin-bottom:.0001pt;text-align:center;line-height:normal'>< a name=ТекстовоеПоле54 ></a ><?=($taxRate > count( $arTaxList) > 0) ? $taxRate."%"
Определения waybill.php:936
$currency
Определения template.php:266
if($inWords) echo htmlspecialcharsbx(Number2Word_Rus(roundEx($totalVatSum $params['CURRENCY']
Определения template.php:799
$items
Определения template.php:224
$matches
Определения index.php:22
$totalCount
Определения subscription_card_product.php:51
$k
Определения template_pdf.php:567
$action
Определения file_dialog.php:21
$propertyFields
Определения yandex_run.php:558
$iterator
Определения yandex_run.php:610
$fields
Определения yandex_run.php:501