View difference between Paste ID: LyEPbQA4 and L9gU1GU6
SHOW: | | - or go back to the newest paste.
1
<?php
2
class CMigration
3
{
4
	private static $_instance;
5
	private static $dir = "/upload/catalog/";
6
	private static $paramFile = "param.php";
7
	private static $catFile = "catalog.php";
8
	private static $lockFile = "process.lock";
9
	private static $debugMode = 1;
10
	//5aaecf6f-0199-11e6-831c-74d43599898f
11
	public static $xmlRegex = "#[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-#i";
12
	public static $translit = Array("replace_space" => '-',"replace_other" => '-');
13
	public static $priceID = 5;
14
	public static $params = Array();
15
16
	public static $propsExeption = Array(
17
		"CML2_BAR_CODE",
18
		"TIP_TSENY_KOLLEROVKI",
19
		"CML2_ARTICLE",
20
		"CML2_LINK",
21
		"CML2_ATTRIBUTES",
22
		"CML2_TRAITS",
23
		"CML2_BASE_UNIT",
24
		"CML2_TAXES",
25
		"GROUP_NAME_LIST",
26
		"FILES",
27
		"R",
28
		"G",
29
		"B",
30
	);
31
32
	public static $linkerProperties = Array(
33
		"CML2_MANUFACTURER", //Производитель
34
		"BRAND", //Производитель
35
		"WORK_TYPE", //Тип работ
36
		"OBJECT_TYPE", //Тип объекта
37
		"WORK_MATERIAL", //Материал рабочей поверхности
38
		"LKM_TYPE", //Тип ЛКМ
39
		"THINNER", //Разбавитель
40
		"BASE", //База
41
		"COLOR", //Цвет
42
		"VOLUME_L", //Объем, л
43
		"VOLUME_KG", //Объем, кг
44
		"PLOTNOST", //Плотность
45
		"KVADRATURA", //Квадратура, кв.м
46
		"LENGTH", //Длина, мм
47
		"CHIPS_SIZE", //Размер крошки, мм
48
		"SEQUIN_COLOR", //Цвет блёсток
49
		"SEQUIN_SIZE", //Размер блёсток, мм
50
		"GLOSS", //Степень блеска
51
52
	);
53
54
	private static $noUpdateHandler = false;
55
56
	private static function setNoHandler($bool)
57
	{
58
		self::$noUpdateHandler=$bool;
59
	}
60
61
	public static function getNoHandler()
62
	{
63
		return self::$noUpdateHandler;
64
	}
65
66
	public static function exception($s)
67
	{
68
		if(self::$debugMode)
69
		{
70
			printra(func_get_args());
71
		}
72
		else
73
		{
74
			throw new Exception(func_get_args());
75
		}
76
	}
77
78
	private static function lock()
79
	{
80
		$docRoot = $_SERVER["DOCUMENT_ROOT"];
81
		touch($docRoot.self::$dir.self::$lockFile);
82
	}
83
84
	private static function locked()
85
	{
86
		$docRoot = $_SERVER["DOCUMENT_ROOT"];
87
		$sFile = $docRoot.self::$dir.self::$lockFile;
88
		$locktime = 1800;
89
		
90
		if (file_exists($sFile) && (time() - filemtime($sFile)) < $locktime) {
91
			unset($sFile);
92
		}
93
		
94
		return file_exists($sFile);
95
	}
96
97
	private static function unlock()
98
	{
99
		$docRoot = $_SERVER["DOCUMENT_ROOT"];
100
		@unlink($docRoot.self::$dir.self::$lockFile);
101
	}
102
103
	public static function getParams()
104
	{
105
		$docRoot = $_SERVER["DOCUMENT_ROOT"];
106
		$arParams = Array();
107
		require($docRoot.self::$dir.self::$paramFile);
108
		return $arParams;
109
	}
110
111
	public static function setParams($arParams=Array())
112
	{
113
		$docRoot = $_SERVER["DOCUMENT_ROOT"];
114
		ArrayToFile($arParams,"arParams",$docRoot.self::$dir.self::$paramFile);
115
		return $arParams;
116
	}
117
118
	public static function logToFile($sStr)
119
	{
120
		$sErrorLog = $_SERVER['DOCUMENT_ROOT']."/upload/catalog/log/".date("Y.m.d").".txt";
121
		$hFile = fopen($sErrorLog,"a+");
122
		fputs($hFile,date("Y.m.d H:i:s")."\t".$sStr."\n");
123
		fclose($hFile);
124
	}
125
126
	public static function cron()
127
	{
128
		try
129
		{
130
			if(!self::locked())
131
			{
132
				if(strlen($sAction = self::$params["action"]))
133
				{
134
					self::lock();
135
					self::logToFile("Start: {$sAction}");
136
					self::${"sAction"}();
137
					self::logToFile("End: {$sAction}");
138
					self::unlock();
139
				}
140
			}
141
		}
142
		catch(Exception $e)
143
		{
144
			ob_start();
145
			printr($e);
146
			$sError = ob_get_contents();
147
			ob_end_clean();
148
			self::SendError($sError);
149
			return false;
150
		}
151
		return true;
152
	}
153
154
	public static function next()
155
	{
156
		$arParams = self::getParams();
157
		if(!$arParams["action"] || $arParams["action"]=="done") return false;
158
		global $APPLICATION;
159
		echo '
160
				<script>
161
					window.setTimeout(function() {
162
						window.location.href = "'.$APPLICATION->GetCurPage().'";
163
					}, "300");
164
				</script>
165
			';
166
	}
167
168
	public static function SendError($sError)
169
	{
170
		$obEvent = new CEvent();
171
		$obEvent->Send("CRON_ERROR","s1",Array("ERROR"=>$sError));
172
		printr($sError);
173
	}
174
175
	public static function checkStart()
176
	{
177
		$sFunctionName = "CMigration::start();";
178
		$obAgent = new CAgent();
179
		$obExists = $obAgent->GetList(Array(), Array("NAME" => $sFunctionName));
180
		if($arExists = $obExists->fetch())
181
		{
182
			$obAgent->Delete($arExists["ID"]);
183
		}
184
		$arAdd = Array(
185
			"NAME" => $sFunctionName,
186
			"AGENT_INTERVAL" => 1,
187
			"NEXT_EXEC" => date("d.m.Y H:i:s", time() + 60),
188
			"IS_PERIOD" => "N"
189
		);
190
		$obAgent->Add($arAdd);
191
	}
192
193
	public static function start()
194
	{
195
		self::removeIBlockLink();
196
		self::syncProperties();
197
		self::setParams(Array("action"=>"syncSections"));
198
	}
199
200
	public static function removeIBlockLink()
201
	{
202
		CCatalog::UnLinkSKUIBlock(IB_SKU);
203
	}
204
205
	public static function GetLinkerIBlocks()
206
	{
207
		if(!isset($GLOBALS["L_IBLOCK"]))
208
		{
209
			$GLOBALS["LINKER_IBLOCK"]=Array();
210
			$obIBlocks = CIBlock::GetList(Array("ID"=>"ASC"),Array("TYPE"=>"links"));
211
			while($arIBlock = $obIBlocks->Fetch())
212
			{
213
				$GLOBALS["L_IBLOCK"][$arIBlock["CODE"]]=$arIBlock["ID"];
214
			}
215
		}
216
		return $GLOBALS["L_IBLOCK"];
217
	}
218
219
	public static function processLinkerIBlock($arProperty)
220
	{
221
		$iIBlockID=false;
222
		if(!empty($arProperty) && $arProperty["CODE"])
223
		{
224
			$arIBlocks = self::GetLinkerIBlocks();
225
			global $APPLICATION;
226
			$arFields = Array(
227
				"SORT"=>$arProperty["SORT"],
228
				"CODE" => ToUpper(trim($arProperty["CODE"])),
229
				"IBLOCK_TYPE_ID" => "links",
230
				"NAME" => self::cleanString($arProperty["NAME"]),
231
				"VERSION" => 2,
232
				"WORKFLOW" => "N",
233
				"SITE_ID" => Array("s1"),
234
				"GROUP_ID" => Array("2" => "R")
235
			);
236
			$arFields["DETAIL_PAGE_URL"]="/catalog/fil-".ToLower($arFields["CODE"])."-is-#CODE#/";
237
238
			$obNewIBlock = new CIBlock();
239
			$arSettings = Array();
240
			$arSettings["CODE"]["WF_TYPE"] = "N";
241
			$arSettings["CODE"]["IS_REQUIRED"] = "Y";
242
			$arSettings["CODE"]["DEFAULT_VALUE"]["UNIQUE"] = "Y";
243
			$arSettings["CODE"]["DEFAULT_VALUE"]["TRANSLITERATION"] = "Y";
244
245
			if(!isset($arIBlocks[$arProperty["CODE"]]))
246
			{
247
				if(!($iIBlockID = $obNewIBlock->Add($arFields)))
248
				{
249
					self::exception("AF: Error creating infoblock - ".$obNewIBlock->LAST_ERROR);
250
					$APPLICATION->ThrowException("AF: Error creating infoblock - ".$obNewIBlock->LAST_ERROR);
251
				}
252
			}
253
			else
254
			{
255
				$iIBlockID = $arIBlocks[$arProperty["CODE"]];
256
				/*if(!($obNewIBlock->Update($iIBlockID, $arFields)))
257
				{
258
					self::exception("AF: Error creating infoblock - ".$obNewIBlock->LAST_ERROR);
259
					$APPLICATION->ThrowException("AF: Error creating infoblock - ".$obNewIBlock->LAST_ERROR);
260
				}*/
261
			}
262
			CIBlock::SetFields($iIBlockID, $arSettings);
263
		}
264
		return $iIBlockID;
265
	}
266
267
	public static function syncProperties()
268
	{
269
		$obSkuProperties = CIBlockProperty::GetList(Array(),Array("IBLOCK_ID"=>IB_CATALOG));
270
		$arSkuProperties = Array();
271
		while($arSkuProperty = $obSkuProperties->Fetch())
272
		{
273
			$arSkuProperties[$arSkuProperty["CODE"]]=$arSkuProperty;
274
		}
275
276
		$obCatProperties = CIBlockProperty::GetList(Array(),Array("IBLOCK_ID"=>IB_SKU));
277
		$arCatProperties = Array();
278
		$iPropertySort=0;
279
		while($arCatProperty = $obCatProperties->Fetch())
280
		{
281
			if(in_array($arCatProperty["CODE"],self::$propsExeption)) continue;
282
			if(preg_match("#^CML2_#",$arCatProperty["XML_ID"]) || preg_match(self::$xmlRegex,$arCatProperty["XML_ID"]))
283
			{
284
285
				switch($arCatProperty["PROPERTY_TYPE"])
286
				{
287
					case "F":
288
						$arPropertyFields = Array(
289
							"NAME" => $arCatProperty["NAME"],
290
							"ACTIVE" => "Y",
291
							"SORT" => $iPropertySort,
292
							"CODE" => $arCatProperty["CODE"],
293
							"PROPERTY_TYPE" => "F",
294
							"IBLOCK_ID" => IB_CATALOG,
295
							"WITH_DESCRIPTION" => "Y",
296
							"MULTIPLE"=>"Y",
297
							"XML_ID"=>""
298
						);
299
					break;
300
					default:
301
						$arPropertyFields = Array(
302
							"NAME" => $arCatProperty["NAME"],
303
							"ACTIVE" => "Y",
304
							"SORT" => $iPropertySort,
305
							"CODE" => $arCatProperty["CODE"],
306
							"PROPERTY_TYPE" => "S",
307
							"IBLOCK_ID" => IB_CATALOG,
308
							"WITH_DESCRIPTION" => "Y",
309
							"MULTIPLE"=>"Y",
310
							"MULTIPLE_CNT"=>1,
311
							"XML_ID"=>""
312
						);
313
						if(in_array($arCatProperty["CODE"], self::$linkerProperties) && ($iIBlockID = self::processLinkerIBlock($arPropertyFields)))
314
						{
315
							$arPropertyFields["PROPERTY_TYPE"]="E";
316
							$arPropertyFields["LINK_IBLOCK_ID"]=$iIBlockID;
317
						}
318
					break;
319
				}
320
				$obNewProperty = new CIBlockProperty();
321
				$iPropertySort++;
322
				if(!isset($arSkuProperties[$arCatProperty["CODE"]]))
323
				{
324
					if(!$obNewProperty->Add($arPropertyFields))
325
					{
326
						self::exception("AF: Error creating property - ".$obNewProperty->LAST_ERROR,__LINE__);
327
					}
328
				}
329
				else
330
				{
331
					$iPropertyID = $arSkuProperties[$arCatProperty["CODE"]]["ID"];
332
					//printra("upd ",$iPropertyID,$arPropertyFields);
333
					if(0)
334
					{
335
						//&&!$obNewProperty->Update($iPropertyID,$arPropertyFields)
336
						self::exception("AF: Error updating property - ".$obNewProperty->LAST_ERROR,__LINE__);
337
					}
338
				}
339
				$arSkuProperties[$arCatProperty["CODE"]]=$arPropertyFields;
340
				$arCatProperties[$arCatProperty["CODE"]]=$arCatProperty;
341
			}
342
		}
343
		return true;
344
	}
345
346
	public static function syncSections()
347
	{
348
		$arResult=Array();
349
		/**
350
		 * Get SKU + Catalog Sections
351
		 */
352
		self::setNoHandler(true);
353
		$arSelect = Array(
354
			"ID",
355
			"NAME",
356
			"IBLOCK_ID",
357
			"ACTIVE",
358
			"IBLOCK_SECTION_ID",
359
			"XML_ID",
360
			"SORT",
361
			"UF_*"
362
		);
363
		$obSections = CIBlockSection::getList(
364
			Array("DEPTH_LEVEL"=>"ASC"),
365
			Array("IBLOCK_ID"=>IB_CATALOG),
366
			false,
367
			$arSelect
368
		);
369
370
		while($arSection = $obSections->fetch())
371
		{
372
			$arResult["CATALOG"][$arSection["XML_ID"]]=$arSection;
373
		}
374
375
		$obSections = CIBlockSection::getList(
376
			Array("DEPTH_LEVEL"=>"ASC"),
377
			Array("IBLOCK_ID"=>IB_SKU),
378
			false,
379
			$arSelect
380
		);
381
382
		while($arSection = $obSections->fetch())
383
		{
384
			$arResult["SKU"][$arSection["ID"]]=$arSection;
385
		}
386
		$sHash = md5(serialize($arResult));
387
388
389
		/**
390
		 * Cache block
391
		 */
392
		$iCacheTime=360000000;
393
		$sCacheDir="/migration/sections";
394
		$obCache = new CPHPCache();
395
396
		if(!$obCache->InitCache($iCacheTime, $sHash, $sCacheDir))
397
		{
398
399
			$obCache->StartDataCache();
400
401
			global $CACHE_MANAGER;
402
			$CACHE_MANAGER->StartTagCache($sCacheDir);
403
			$obNewSection = new CIBlockSection();
404
			foreach($arResult["SKU"] as $arSection)
405
			{
406
				$sCRC = md5(serialize($arSection));
407
				$arFields = Array(
408
					"IBLOCK_ID"=>IB_CATALOG,
409
					"ACTIVE"=>$arSection["ACTIVE"],
410
					"UF_CRC"=>$sCRC,
411
					"SORT"=>$arSection["SORT"],
412
					"NAME"=>$arSection["NAME"],
413
					"XML_ID"=>"cat_{$arSection["ID"]}",
414
					"IBLOCK_SECTION_ID"=>$arResult["CATALOG"]["cat_{$arSection["IBLOCK_SECTION_ID"]}"]["ID"],
415
					"CODE"=>CUtil::translit($arSection["NAME"],"ru",self::$translit)
416
				);
417
				if(isset($arResult["CATALOG"]["cat_{$arSection["ID"]}"]))
418
				{
419
					$arCatSection = $arResult["CATALOG"]["cat_{$arSection["ID"]}"];
420
					if($arCatSection["UF_CRC"]!=$sCRC)
421
					{
422
						if(!$obNewSection->Update($arCatSection["ID"],$arFields,false))
423
						{
424
							self::exception($obNewSection->LAST_ERROR,$arFields);
425
						}
426
					}
427
				}
428
				else
429
				{
430
					if($iItemID = $obNewSection->Add($arFields,false))
431
					{
432
						$arResult["CATALOG"]["cat_{$arSection["ID"]}"]=Array("ID"=>$iItemID)+$arFields;
433
					}
434
					else
435
					{
436
						self::exception($obNewSection->LAST_ERROR,$arFields);
437
					}
438
				}
439
			}
440
441
			/**
442
			 * Deactivate sections
443
			 */
444
			/*foreach($arResult["CATALOG"] as $arCatSection)
445
			{
446
				if(preg_match("#^cat_(\d+)$#",$arCatSection["XML_ID"],$arMatches))
447
				{
448
					$iSKUSectionID = IntVal($arMatches[1]);
449
					if(isset($ar))
450
				}
451
			}*/
452
453
454
			CIBlockSection::ReSort(IB_CATALOG);
455
456
			$CACHE_MANAGER->RegisterTag(IB_CATALOG);
457
			$CACHE_MANAGER->EndTagCache();
458
459
			$obCache->EndDataCache($arResult);
460
		}
461
		else
462
		{
463
			$arResult = $obCache->GetVars();
464
		}
465
466
		self::setNoHandler(false);
467
		self::setParams(Array("action"=>"saveFiles"));
468
		return true;
469
	}
470
471
	public static function saveFiles()
472
	{
473
		$docRoot = $_SERVER["DOCUMENT_ROOT"];
474
475
		/**
476
		 * Get Linker IBlocks Values
477
		 * $GLOBALS["LINK_IB"][$iIBlockID][$sName]=$iItemID;
478
		 */
479
480
		$GLOBALS["LINK_IB"]=Array();
481
		$obItems = \Bitrix\Iblock\ElementTable::getList(
482
			Array(
483
				"filter"=>Array(
484
					"IBLOCK.TYPE.ID"=>"links",
485
					"WF_PARENT_ELEMENT_ID"=>false
486
				),
487
				"select"=>Array("*")
488
			)
489
		);
490
		$GLOBALS["LINK_IB"]=Array();
491
		while($arItem = $obItems->Fetch())
492
		{
493
			$GLOBALS["LINK_IB"][$arItem["IBLOCK_ID"]][$arItem["NAME"]]=$arItem["ID"];
494
		}
495
496
		/**
497
		 * Get SKU Section Links
498
		 */
499
500
		$obItemSections = \Bitrix\Iblock\SectionElementTable::getList(
501
			Array(
502
				"filter" => Array(
503
					"IBLOCK_SECTION.IBLOCK_ID" => IB_SKU
504
				)
505
			)
506
		);
507
		$arItemToSections = Array();
508
		while($arItem = $obItemSections->Fetch())
509
		{
510
			$arItemToSections[$arItem["IBLOCK_ELEMENT_ID"]][]=$arItem["IBLOCK_SECTION_ID"];
511
		}
512
513
		/**
514
		 * Get Section to section Link
515
		 */
516
517
		$obSections = \Bitrix\Iblock\SectionTable::getList(Array(
518
			"filter"=>Array(
519
				"IBLOCK_ID"=>IB_CATALOG
520
			),
521
			"select"=>Array("ID","XML_ID")
522
		));
523
		$arSKUSectionToCatSection=Array();
524
		while($arSection = $obSections->fetch())
525
		{
526
			if(preg_match("#^cat_(\d+)$#",$arSection["XML_ID"],$arMatches))
527
			{
528
				$arSKUSectionToCatSection[$arMatches[1]]=$arSection["ID"];
529
			}
530
		}
531
532
		/**
533
		 * Get Properties link
534
		 */
535
		$obSkuProperties = CIBlockProperty::GetList(Array(),Array("IBLOCK_ID"=>IB_SKU));
536
537
		$arProperties = Array();
538
		$iGroupNameID = 0;
539
		$iGroupListNameID = 0;
540
		while($arSkuProperty = $obSkuProperties->Fetch())
541
		{
542
			if($arSkuProperty["CODE"]=="GROUP_NAME") $iGroupNameID=$arSkuProperty["ID"];
543
			if($arSkuProperty["CODE"]=="GROUP_NAME_LIST") $iGroupListNameID=$arSkuProperty["ID"];
544
			$arSkuProperties[$arSkuProperty["CODE"]]=$arSkuProperty["ID"];
545
			$arProperties[$arSkuProperty["ID"]]=$arSkuProperty;
546
		}
547
548
549
		$obCatProperties = CIBlockProperty::GetList(Array(),Array("IBLOCK_ID"=>IB_CATALOG));
550
		$arPropertiesCatalogToSKULink = Array();
551
		$arCRCProperties = Array();
552
		while($arCatProperty = $obCatProperties->Fetch())
553
		{
554
			if(substr_count($arCatProperty["CODE"],"CRC_"))
555
			{
556
				$arCRCProperties[]=$arCatProperty["CODE"];
557
				continue;
558
			}
559
			if(isset($arSkuProperties[$arCatProperty["CODE"]]))
560
			{
561
				$arPropertiesCatalogToSKULink[$arSkuProperties[$arCatProperty["CODE"]]]=$arCatProperty["CODE"];
562
			}
563
		}
564
565
		/**
566
		 * Get Properties enum values
567
		 */
568
		$arPropertyEnumToValue=Array();
569
		$arPropertyEnumToXMLID=Array();
570
		foreach($arProperties as $iPropertyID=>$arProperty)
571
		{
572
			if($arProperty["PROPERTY_TYPE"]=="L")
573
			{
574
				$obEnum = CIBlockProperty::GetPropertyEnum($iPropertyID);
575
				while($arItem = $obEnum->Fetch())
576
				{
577
					$arPropertyEnumToValue[$arItem["ID"]]=$arItem["VALUE"];
578
					$arPropertyEnumToXMLID[$arItem["ID"]]=$arItem["XML_ID"];
579
				}
580
			}
581
582
		}
583
584
		/**
585
		 * Get Catalog element links
586
		 */
587
		$arSSelect = Array("ID","XML_ID");
588
		foreach($arCRCProperties as $sCode) $arSSelect[]="PROPERTY_{$sCode}";
589
		$obCatItems = CIBlockElement::GetList(Array(),Array("IBLOCK_ID"=>IB_CATALOG),false,false,$arSSelect);
590
		$arCatItemsLink = Array();
591
		while($arCatItem = $obCatItems->fetch())
592
		{
593
			$arCatItemsLink[$arCatItem["XML_ID"]]=$arCatItem;
594
		}
595
596
597
		/**
598
		 * Get SKU With Properties and Prices
599
		 */
600
601
		$arLinkerIBlocks = self::GetLinkerIBlocks();
602
603
		$iTime = microtime(1);
604
		$arSelect = Array(
605
			"ID",
606
			"XML_ID",
607
			"NAME",
608
			"ACTIVE",
609
			"PROPERTY_*",
610
			"PROPERTY_ENUM_*",
611
			"PROPERTY_XML_ID_*",
612
			"CATALOG_QUANTITY"
613
		);
614
		$arSelect[]="CATALOG_GROUP_".BASE_PRICE_ID;
615
616
617
		$obSKUItems = CIBlockElement::GetList(
618
			Array(),
619
			Array(
620
				"ACTIVE"=>"Y",
621
				"IBLOCK_ID" => IB_SKU,
622
				Array(
623
					"LOGIC"=>"OR",
624
					Array("!PROPERTY_GROUP_NAME"=>false),
625
					Array("!PROPERTY_GROUP_NAME_LIST"=>false)
626
				)
627
			),
628
			false,
629
			false,
630
			$arSelect
631
		);
632
633
634
		$arResult = Array();
635
636
		while($arItem = $obSKUItems->Fetch())
637
		{
638
			$sGroupName = self::cleanString($arItem["PROPERTY_{$iGroupNameID}"]);
639
			$sGroupNameList = self::cleanString($arPropertyEnumToValue[$arItem["PROPERTY_{$iGroupListNameID}"]]);//self::cleanString($arItem["PROPERTY_{$iGroupNameID}"]);
640
641
			$sGroupNameListXML = $arPropertyEnumToXMLID[$arItem["PROPERTY_{$iGroupListNameID}"]];
642
643
			unset($arItem["PROPERTY_{$iGroupNameID}"]);
644
			unset($arItem["DESCRIPTION_{$iGroupNameID}"]);
645
			if(!$sGroupName && !$sGroupNameListXML) continue;
646
			$sToMD5 = $sGroupNameListXML?:CUtil::translit($sGroupName,"ru",self::$translit);
647
			$sGroupXMLID = "cat_".md5($sToMD5);
648
649
			if(!isset($arResult[$sGroupXMLID]))
650
			{
651
				$sElementName = $sGroupNameList?:$sGroupName;
652
				$arResult[$sGroupXMLID]=Array(
653
					"FIELDS"=>Array(
654
						"IBLOCK_ID"=>IB_CATALOG,
655
						"ACTIVE"=>"Y",
656
						"NAME" => $sElementName,
657
						"XML_ID" => $sGroupXMLID,
658
						"CODE"=>CUtil::translit($sGroupName,"ru",self::$translit),
659
						"CATALOG_AVAILABLE"=>"N",
660
						"CATALOG_QUANTITY"=>0
661
					),
662
					"PROPERTIES"=>Array("ACTIVE"=>false),
663
					"SECTIONS"=>Array(),
664
					"PRICES"=>Array(),
665
					"SKU_ITEMS"=>Array(),
666
					"CRC"=>Array()
667
				);
668
			}
669
			$arCatItem = &$arResult[$sGroupXMLID];
670
			$arCatItemFields = &$arCatItem["FIELDS"];
671
			$arCatItemProperties = &$arCatItem["PROPERTIES"];
672
			$arCatItemSections = &$arCatItem["SECTIONS"];
673
			$arCatPrices = &$arCatItem["PRICES"];
674
			$arCatItemSKU = &$arCatItem["SKU_ITEMS"];
675
676
677
			/**
678
			 * Заполненные значения в каталоге + CRC
679
			 */
680
681
			if(isset($arCatItemsLink[$sGroupXMLID]))
682
			{
683
				$arWasCatItem = $arCatItemsLink[$sGroupXMLID];
684
				$arCatItemFields["ID"]=$arWasCatItem["ID"];
685
				foreach($arWasCatItem as $sCode=>$sValue)
686
				{
687
					if(preg_match("#^PROPERTY_CRC_(\S+)_VALUE$#",$sCode,$arMatches))
688
					{
689
						$arCatItem["CRC"][$arMatches[1]]=$sValue;
690
					}
691
				}
692
			}
693
			else
694
			{
695
				//printr($arCatItem["FIELDS"]["NAME"],$sGroupXMLID);
696
			}
697
698
			/**
699
			 * Перегон разделов
700
			 */
701
			if(isset($arItemToSections[$arItem["ID"]]) && $sGroupXMLID)
702
			{
703
				foreach($arItemToSections[$arItem["ID"]] as $iSectionID)
704
				{
705
					if(isset($arSKUSectionToCatSection[$iSectionID]))
706
					{
707
						$iCatSectionID = $arSKUSectionToCatSection[$iSectionID];
708
						if(!in_array($iCatSectionID,$arCatItemSections))
709
						{
710
							$arCatItemSections[]=$iCatSectionID;
711
						}
712
					}
713
				}
714
			}
715
716
			/**
717
			 * Перегон всех свойств в формат свойств для каталога.
718
			 */
719
			foreach($arItem as $sCode=>$arValues)
720
			{
721
				if(preg_match("#^PROPERTY_(\d+)$#",$sCode,$arMatches))
722
				{
723
					$iPropertyID = IntVal($arMatches[1]);
724
					if(isset($arPropertiesCatalogToSKULink[$iPropertyID]))
725
					{
726
						if(!is_array($arValues))
727
						{
728
							$arValues = Array($arValues);
729
							$arItem["DESCRIPTION_{$iPropertyID}"]=Array($arItem["DESCRIPTION_{$iPropertyID}"]);
730
						}
731
						$iCatPropertyID = $arPropertiesCatalogToSKULink[$iPropertyID];
732
						if(!isset($arCatItemProperties[$iCatPropertyID]))
733
						{
734
							$arCatItemProperties[$iCatPropertyID]=Array();
735
						}
736
						$sPropertyType = $arProperties[$iPropertyID]["PROPERTY_TYPE"];
737
						$sPropertyCode = $arProperties[$iPropertyID]["CODE"];
738
739
						foreach($arValues as $iKey=>$value)
740
						{
741
							switch($sPropertyType)
742
							{
743
								case "L":
744
									$enumID = $value;
745
									$value=$arPropertyEnumToValue[$value];
746
747
									if(in_array($sPropertyCode,self::$linkerProperties) && (isset($arLinkerIBlocks[$sPropertyCode])))
748
									{
749
750
751
										if($sPropertyCode=="WORK_TYPE")
752
										{
753
											$arValuesStr = explode("/",$value);
754
											$value = Array();
755
											foreach($arValuesStr as $iKey=>$sValue)
756
											{
757
												if($sValue = trim($sValue))
758
												{
759
													$value[]=CIBlockExt::TouchPropertyElement($sValue,$arLinkerIBlocks[$sPropertyCode]);
760
												}
761
											}
762
										}
763
										elseif($sPropertyCode=="COLOR")
764
										{
765
											$value=CIBlockExt::TouchPropertyElement($value,$arLinkerIBlocks[$sPropertyCode], $arPropertyEnumToXMLID[$enumID]);
766
										}
767
										else
768
										{
769
											$value=CIBlockExt::TouchPropertyElement($value,$arLinkerIBlocks[$sPropertyCode]);
770
										}
771
772
773
									}
774
								break;
775
								default:
776
								break;
777
							}
778
							if(!is_array($value))
779
							{
780
								$value=self::cleanString($value);
781
								$sDescription = self::cleanString($arItem["DESCRIPTION_{$iPropertyID}"][$iKey]);
782
							}
783
							else
784
							{
785
								if(empty($value))
786
								{
787
									$value=false;
788
								}
789
							}
790
791
							/*if(!in_array($value,$arCatItemProperties[$iCatPropertyID]["VALUE"]))
792
							{
793
								$arCatItemProperties[$iCatPropertyID]["VALUE"][$iKey]=$value;
794
								$arCatItemProperties[$iCatPropertyID]["DESCRIPTION"][$iKey]=$sDescription;
795
							}*/
796
							/**
797
							 * Hack with no description. Upper variant doesn't work. Debug yourself.
798
							 */
799
							if(is_array($value))
800
							{
801
								foreach($value as $oneValue)
802
								{
803
									if(!in_array($oneValue,$arCatItemProperties[$iCatPropertyID]))
804
									{
805
										$arCatItemProperties[$iCatPropertyID][]=$oneValue;
806
									}
807
								}
808
							}
809
							elseif(!in_array($value,$arCatItemProperties[$iCatPropertyID]))
810
							{
811
								$arCatItemProperties[$iCatPropertyID][]=$value;
812
							}
813
						}
814
						if(empty($arCatItemProperties[$iCatPropertyID])) $arCatItemProperties[$iCatPropertyID]=false;
815
					}
816
817
				}
818
			}
819
820
821
			/**
822
			 * Перегон цен и остатков
823
			 */
824
			if($iPrice = FloatVal($arItem["CATALOG_PRICE_".BASE_PRICE_ID]))
825
			{
826
827
				if(($sCurrency = $arItem["CATALOG_CURRENCY_".BASE_PRICE_ID])!="RUB")
828
				{
829
					$iPrice = CCurrencyRates::ConvertCurrency($iPrice,$sCurrency,"RUB");
830
				}
831
				if(($arItem["CATALOG_QUANTITY"]>0) && ($iPrice>0))
832
				{
833
					$arCatItemFields["CATALOG_AVAILABLE"]="Y";
834
					$arCatItemFields["CATALOG_QUANTITY"]+=$arItem["CATALOG_QUANTITY"];
835
					$arCatItemProperties["ACTIVE"]=1;
836
					$arCatPrices[]=$iPrice;
837
				}
838
			}
839
			$arCatItemSKU[]=$arItem["ID"];
840
		}
841
//die();
842
		ArrayToFile($arResult, "arCatItems", $docRoot.self::$dir.self::$catFile);
843
		//die();
844
		self::setParams(Array("action"=>"processCatalogItems"));
845
		return true;
846
	}
847
848
	public static function arrayCRC($array)
849
	{
850
		return md5(serialize($array));
851
	}
852
853
	public static function processCatalogItems()
854
	{
855
		$docRoot = $_SERVER["DOCUMENT_ROOT"];
856
		/**
857
		 * @var $arCatItems array
858
		 */
859
		include($docRoot.self::$dir.self::$catFile);
860
861
		$obNewElement = new CIBlockElement();
862
863
		$iTime = microtime(1);
864
		$bAnotherTime = false;
865
866
		self::setNoHandler(true);
867
		$iProcessed = 0;
868
		foreach($arCatItems as $iKey=>$arElement)
869
		{
870
			$iProcessed++;
871
			if(IntVal($arElement["PROCESSED"])) continue;
872
			$bUpdated = false;
873
			$iCatElementID = 0;
874
875
876
			/**
877
			 * Create catalog element
878
			 */
879
			if(IntVal($arElement["FIELDS"]["ID"]))
880
			{
881
				$iCatElementID=$arElement["FIELDS"]["ID"];
882
				
883
				if(self::arrayCRC($arElement["FIELDS"])!=$arElement["CRC"]["FIELDS"])
884
				{
885
					unset($arElement["FIELDS"]["CODE"]);
886
					if(!$obNewElement->Update($iCatElementID,$arElement["FIELDS"]))
887
					{
888
						self::exception($obNewElement->LAST_ERROR,$arElement["FIELDS"],__LINE__);
889
					}
890
					$arCatalogUpdate=Array(
891
						"ID"=>$iCatElementID,
892
						"AVAILABLE"=>$arElement["FIELDS"]["CATALOG_AVAILABLE"],
893
						"QUANTITY"=>$arElement["FIELDS"]["CATALOG_QUANTITY"]
894
					);
895
					CCatalogProduct::Add($arCatalogUpdate);
896
					$bUpdated=true;
897
				}
898
			}
899
			else
900
			{
901
				///printra($arElement);
902
903
				if(!($iCatElementID = $obNewElement->Add($arElement["FIELDS"])))
904
				{
905
					self::exception($obNewElement->LAST_ERROR,$arElement["FIELDS"],__LINE__);
906
				}
907
			}
908
909
			/**
910
			 * Set sections
911
			 */
912
913
			if(self::arrayCRC($arElement["SECTIONS"])!=$arElement["CRC"]["SECTIONS"])
914
			{
915
				CIBlockElement::SetElementSection($iCatElementID,$arElement["SECTIONS"]);
916
				$bUpdated=true;
917
			}
918
919
			/**
920
			 * Set properties
921
			 */
922
923
			$arElement["PROPERTIES"]["PRICE_FROM"]=min($arElement["PRICES"]);
924
			$arElement["PROPERTIES"]["PRICE_TO"]=max($arElement["PRICES"]);
925
			$sCurrentCRC=self::arrayCRC($arElement["PROPERTIES"]);
926
			$arNewCRC = Array(
927
				"CRC_PROPERTIES"=>self::arrayCRC($arElement["PROPERTIES"]),
928
				"CRC_SECTIONS"=>self::arrayCRC($arElement["SECTIONS"]),
929
				"CRC_FIELDS"=>self::arrayCRC($arElement["FIELDS"]),
930
				"CRC_SKU_ITEMS"=>self::arrayCRC($arElement["SKU_ITEMS"]),
931
			);
932
			$arElement["PROPERTIES"]+=$arNewCRC;
933
934
935
			if($bUpdated || ($sCurrentCRC!=$arElement["CRC"]["PROPERTIES"]))
936
			{
937
				CIBlockElement::SetPropertyValuesEx($iCatElementID,IB_CATALOG,$arElement["PROPERTIES"]);
938
				$bUpdated=true;
939
			}
940
941
			/**
942
			 * Link SKU Items
943
			 */
944
			if(self::arrayCRC($arElement["SKU_ITEMS"])!=$arElement["CRC"]["SKU_ITEMS"])
945
			{
946
				foreach($arElement["SKU_ITEMS"] as $iSKUItemID)
947
				{
948
					CIBlockElement::SetPropertyValuesEx($iSKUItemID,IB_SKU,Array("CML2_LINK"=>$iCatElementID));
949
				}
950
				$bUpdated=true;
951
				
952
			}
953
954
			if($bUpdated)
955
			{
956
				//CIBlockElement::UpdateSearch($iCatElementID,true);
957
				CIBlockExt::RunUpdate($iCatElementID);
958
				CCacheClean::CatalogElement($iCatElementID);
959
				\Bitrix\Iblock\PropertyIndex\Manager::updateElementIndex(IB_CATALOG, $iCatElementID);
960
			}
961
962
			$arCatItems[$iKey]=Array(
963
				"PROCESSED"=>1,
964
				"ID"=>$iCatElementID
965
			);
966
			if(time()-$iTime>15)
967
			{
968
				$bAnotherTime = true;
969
				break;
970
			}
971
		}
972
973
		self::setNoHandler(false);
974
975
		ArrayToFile($arCatItems, "arCatItems", $docRoot.self::$dir.self::$catFile);
976
		if($bAnotherTime)
977
		{
978
			$params = self::getParams();
979
			$params["processed"] = "{$iProcessed} / ".count($arCatItems);
980
			self::logToFile("Processed ".$params["processed"]);
981
			self::setParams($params);
982
		}
983
		else
984
		{
985
			self::setParams(Array("action"=>"deactivateItems"));
986
		}
987
		return !$bAnotherTime;
988
	}
989
990
	public static function deactivateItems()
991
	{
992
		$docRoot = $_SERVER["DOCUMENT_ROOT"];
993
		/**
994
		 * @var $arCatItems array
995
		 */
996
		require($docRoot.self::$dir.self::$catFile);
997
998
		$bAnotherTime = false;
999
		$iTime = microtime(1);
1000
		$obNewElement = new CIBlockElement();
1001
		self::setNoHandler(true);
1002
		$iProcessed=0;
1003
		$arIDs = Array();
1004
		foreach($arCatItems as $arItem)
1005
		{
1006
			$arIDs[]=$arItem["ID"];
1007
		}
1008
1009
		$iCount = 0;
1010
		if(!empty($arIDs))
1011
		{
1012
			$obItems = $obNewElement->GetList(
1013
				Array(),
1014
				Array(
1015
					"IBLOCK_ID"=>IB_CATALOG,
1016
					"ACTIVE"=>"Y",
1017
					"!ID"=>$arIDs
1018
				),
1019
				false,
1020
				false,
1021
				Array("ID")
1022
			);
1023
			$iCount=$obItems->SelectedRowsCount();
1024
1025
1026
			while($arItem = $obItems->Fetch())
1027
			{
1028
				$iProcessed++;
1029
				$obNewElement->Update($arItem["ID"],Array("ACTIVE"=>"N"));
1030
				if(time()-$iTime>15)
1031
				{
1032
					$bAnotherTime=true;
1033
					break;
1034
				}
1035
			}
1036
		}
1037
1038
1039
1040
		if($bAnotherTime)
1041
		{
1042
			$params = self::getParams();
1043
			$params["processed"] = "{$iProcessed} / ".$iCount;
1044
			self::setParams($params);
1045
			self::logToFile("Processed ".$params["processed"]);
1046
			ArrayToFile($arCatItems, "arCatItems", $docRoot.self::$dir.self::$catFile);
1047
		}
1048
		else
1049
		{
1050
			//self::setParams(Array());
1051
			self::setParams(Array("action"=>"updateSearch"));
1052
		}
1053
		self::setNoHandler(false);
1054
		return !$bAnotherTime;
1055
	}
1056
	
1057
	public static function updateSearch()
1058
	{
1059
		$obInstance = new CYandexSearch;
1060
		$obInstance->SaveYMLFile();
1061
		self::setParams(Array());
1062
		return true;
1063
	}
1064
1065
	public static function cleanString($s)
1066
	{
1067
		return trim(preg_replace("#[ ]+#", " ", $s));
1068
	}
1069
1070
	private function __clone(){}
1071
1072
	private function __construct()
1073
	{
1074
		$docRoot = $_SERVER["DOCUMENT_ROOT"];
1075
		CheckDirPath($docRoot.self::$dir);
1076
		touch($docRoot.self::$dir.self::$paramFile);
1077
		touch($docRoot.self::$dir.self::$catFile);
1078
		self::$params=self::getParams();
1079
	}
1080
1081
	public static function getInstance()
1082
	{
1083
		if(null === self::$_instance)
1084
		{
1085
			self::$_instance = new self();
1086
		}
1087
		return self::$_instance;
1088
	}
1089
}