Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
import.php
1<?php
2
4
17
22class Import extends Base
23{
24 public const ACTION = 'import';
25 public const ERROR_MANIFEST_IS_NOT_AVAILABLE = 'ERROR_MANIFEST_IS_NOT_AVAILABLE';
26
27 private const STEP_INIT_BACKGROUND = 'init_background';
28 private const STEP_START = 'start';
29 private const STEP_MANIFEST = 'manifest';
30 private const STEP_CLEAN = 'clean';
31 private const STEP_LOAD = 'load';
32 private const STEP_FINISH = 'finish';
33
34 private const STEPS_ORDER = [
35 self::STEP_START,
36 self::STEP_INIT_BACKGROUND,
37 self::STEP_MANIFEST,
38 self::STEP_CLEAN,
39 self::STEP_LOAD,
40 self::STEP_FINISH,
41 ];
42
43 private const COUNT_ADD_FILES_BY_STEP = 200;
44
45 private $manifestCode;
46
53 public function setManifestCode($code): bool
54 {
55 $this->manifestCode = $code;
56
57 return true;
58 }
59
64 public function getManifestCode()
65 {
66 return $this->manifestCode ?? '';
67 }
68
77 public function run(): bool
78 {
79 $result = false;
80 $data = $this->getStructureData();
81
82 if ($this->check($data))
83 {
84 $this->setStatus(self::STATUS_PROCESS);
85 $actionInfo = $this->getSetting()->get(Setting::SETTING_ACTION_INFO);
86 if (!$actionInfo)
87 {
88 $actionInfo = [
89 'setting' => [],
90 'run' => self::STEP_START,
91 'section' => [],
92 'currentSection' => 0,
93 'step' => 0,
94 ];
95 }
96
97 $this->setManifestCode($data['MANIFEST']['CODE']);
98 switch ($actionInfo['run'])
99 {
100 case self::STEP_START:
101 $actionInfo['setting'] = $this->doStart();
102 $actionInfo['section'] = $actionInfo['setting']['section'];
103 break;
104 case self::STEP_INIT_BACKGROUND:
105 $actionInfo['setting'] = $this->doInitBackground($actionInfo, $data);
106 break;
107 case self::STEP_MANIFEST:
108 $actionInfo['setting'] = $this->doInitManifest(
109 $actionInfo['setting']['next'],
110 $actionInfo['step'],
112 );
113 break;
114 case self::STEP_CLEAN:
115 $manifest = Manifest::get($this->getManifestCode());
116 if (
117 (isset($data['MANIFEST']['SKIP_CLEARING']) && $data['MANIFEST']['SKIP_CLEARING'] === 'Y')
118 || (isset($manifest['SKIP_CLEARING']) && $manifest['SKIP_CLEARING'] === 'Y')
119 )
120 {
121 $actionInfo['setting']['finish'] = true;
122 }
123 else
124 {
125 $actionInfo['section']['next'] = $actionInfo['section']['next'] ?? null;
126 $actionInfo['setting'] = $this->doClean(
127 $actionInfo['section'][$actionInfo['currentSection']],
128 $actionInfo['section']['next'],
129 (int) $actionInfo['step']
130 );
131 }
132 break;
133 case self::STEP_LOAD:
134 $actionInfo['setting']['result'] = true;
135 $type = $actionInfo['section'][$actionInfo['currentSection']] ?? false;
136 if ($type && isset($data[self::PROPERTY_STRUCTURE][$type][$actionInfo['step']]))
137 {
138 $path = $data[self::PROPERTY_STRUCTURE][$type][$actionInfo['step']];
139 $http = DataProvider\Controller::getInstance()->get(DataProvider\Controller::CODE_IO);
140 $content = $http->getContent($path, $actionInfo['step']);
141 if (!empty($content['ERROR_CODE']))
142 {
143 $this->getNotificationInstance()->add(
145 'REST_CONFIGURATION_IMPORT_ERROR_CONTENT',
146 [
147 '#STEP#' => $actionInfo['step'],
148 ]
149 ),
150 implode(
151 '_',
152 [
153 $content['ERROR_CODE'],
154 $actionInfo['section'][$actionInfo['currentSection']],
155 $actionInfo['step'],
156 ]
157 ),
159 );
160 }
161 if ($content['COUNT'] === 0)
162 {
163 $content['COUNT'] = count($data[self::PROPERTY_STRUCTURE][$type]);
164 }
165
166 if ($content['SANITIZE'])
167 {
168 $this->getNotificationInstance()->add(
170 'REST_CONFIGURATION_IMPORT_ERROR_SANITIZE_SHORT',
171 [
172 '#STEP#' => $actionInfo['step']
173 ]
174 ),
175 implode(
176 '_',
177 [
178 'SANITIZE',
179 $actionInfo['currentSection'],
180 $actionInfo['step'],
181 ]
182 ),
184 );
185 }
186
187 if (!is_null($content['DATA']))
188 {
189 $actionInfo['setting']['step'] = $actionInfo['setting']['step'] ?? null;
190 $actionInfo['setting'] = $this->doLoad(
191 $actionInfo['setting']['step'],
192 $actionInfo['section'][$actionInfo['currentSection']],
193 $content
194 );
195 }
196 }
197 $actionInfo['setting']['next'] = !$actionInfo['setting']['result'];
198
199 break;
200 case self::STEP_FINISH:
201 $actionInfo['setting'] = $this->doFinish();
202 break;
203 default:
204 $this->setStatus(self::STATUS_FINISH);
205 $this->unregister();
206 break;
207 }
208
209 $exception = $this->getNotificationInstance()->list(
210 [
212 ]
213 );
214 if (!empty($exception))
215 {
216 $this->setStatus(self::STATUS_ERROR);
217 $this->unregister();
218 }
219 else
220 {
221 $actionInfo['step']++;
222 if (
223 !array_key_exists('next', $actionInfo['setting'])
224 || $actionInfo['setting']['next'] === false
225 )
226 {
227 $actionInfo['currentSection']++;
228 $actionInfo['step'] = 0;
229 }
230 if (
231 (
232 !array_key_exists('finish', $actionInfo['setting'])
233 && !isset($actionInfo['section'][$actionInfo['currentSection']])
234 )
235 || (
236 isset($actionInfo['setting']['finish'])
237 && $actionInfo['setting']['finish'] === true
238 )
239 )
240 {
241 $actionInfo['setting']['finish'] = false;
242 $actionInfo['currentSection'] = 0;
243 $actionInfo['step'] = 0;
244 $key = array_search($actionInfo['run'], self::STEPS_ORDER);
245 if ($key !== false)
246 {
247 $key++;
248 }
249 $actionInfo['run'] = self::STEPS_ORDER[$key] ?? false;
250 }
251 }
252
253 $result = $this->getSetting()->set(Setting::SETTING_ACTION_INFO, $actionInfo);
254 }
255 else
256 {
257 $this->setStatus(self::STATUS_ERROR);
258 }
259
260 return $result;
261 }
262
263 protected function check(array $data): bool
264 {
265 $result = false;
266 if (!empty($data[self::PROPERTY_MANIFEST]['CODE']))
267 {
268 $result = true;
269 }
270
271 return $result;
272 }
273
281 public function doInitManifest(?string $next, int $step, string $type): array
282 {
283 $result = [
284 'next' => false,
285 'finish' => true,
286 ];
287 $additionalOption = $this->getSetting()->get(Setting::SETTING_ACTION_ADDITIONAL_OPTION);
289 $this->getManifestCode(),
290 [
291 'TYPE' => $type,
292 'STEP' => $step,
293 'NEXT' => $next,
294 'ITEM_CODE' => '',
295 'CONTEXT_USER' => $this->getContext(),
296 'ADDITIONAL_OPTION' => $additionalOption,
297 ]
298 );
299 foreach ($items as $item)
300 {
301 $this->getNotificationInstance()->save($item);
302 if ($item['NEXT'] !== false)
303 {
304 $result['next'] = $item['NEXT'];
305 $result['finish'] = false;
306 }
307 }
308
309 return $result;
310 }
311
320 public function doClean($code, $step, $next, bool $clearFull = false): array
321 {
322 $result = [
323 'next' => false,
324 ];
325
326 if ($code)
327 {
328 $additionalOption = $this->getSetting()->get(Setting::SETTING_ACTION_ADDITIONAL_OPTION);
329 $data = Controller::callEventClear(
330 [
331 'CODE' => $code,
332 'STEP' => $step,
333 'NEXT' => $next,
334 'CONTEXT' => $this->getContextEntity(),
335 'CONTEXT_USER' => $this->getContext(),
336 'CLEAR_FULL' => $clearFull,
337 'PREFIX_NAME' => Loc::getMessage('REST_CONFIGURATION_INSTALL_CLEAR_PREFIX_NAME'),//todo: lang file
338 'MANIFEST_CODE' => $this->getManifestCode(),
339 'IMPORT_MANIFEST' => Manifest::get($this->getManifestCode()),
340 'ADDITIONAL_OPTION' => $additionalOption,
341 ]
342 );
343
344 $this->getNotificationInstance()->save($data);
345
346 if (isset($data['NEXT']))
347 {
348 $result['next'] = $data['NEXT'];
349 }
350 }
351
352 return $result;
353 }
354
362 public function doLoad($step, $code, $content): array
363 {
364 $result = [
365 'result' => true,
366 ];
367
368 if ($content['COUNT'] > $step)
369 {
370 $result['result'] = false;
371 }
372
373 if (!is_null($content['DATA']))
374 {
375 $ratio = $this->getSetting()->get(Setting::SETTING_RATIO);
376 $additionalOption = $this->getSetting()->get(Setting::SETTING_ACTION_ADDITIONAL_OPTION);
377 $dataList = Controller::callEventImport(
378 [
379 'CODE' => $code,
380 'CONTENT' => $content,
381 'RATIO' => $ratio,
382 'CONTEXT' => $this->getContextEntity(),
383 'CONTEXT_USER' => $this->getContext(),
384 'MANIFEST_CODE' => $this->getManifestCode(),
385 'IMPORT_MANIFEST' => Manifest::get($this->getManifestCode()),
386 'ADDITIONAL_OPTION' => $additionalOption,
387 ]
388 );
389
390 foreach ($dataList as $data)
391 {
392 if (is_array($data['RATIO']))
393 {
394 if (empty($ratio[$code]))
395 {
396 $ratio[$code] = [];
397 }
398 foreach ($data['RATIO'] as $old => $new)
399 {
400 $ratio[$code][$old] = $new;
401 }
402 }
403
404 $this->getNotificationInstance()->save($data);
405 }
406
407 $this->getSetting()->set(Setting::SETTING_RATIO, $ratio);
408 }
409
410 return $result;
411 }
412
420 private function doInitBackground($actionInfo, $data): array
421 {
422 $isEnd = false;
423 $next = $actionInfo['step'];
424 $structure = new Structure($this->setting->getContext());
425
426 if ($data[self::PROPERTY_FILES] && $data[self::PROPERTY_STRUCTURE][Helper::STRUCTURE_FILES_NAME])
427 {
428 $chunkList = array_chunk($data[self::PROPERTY_FILES], self::COUNT_ADD_FILES_BY_STEP);
429 if (!empty($chunkList[$next]))
430 {
431 $structure->addFileList(
432 $chunkList[$next],
433 $data[self::PROPERTY_STRUCTURE][Helper::STRUCTURE_FILES_NAME]
434 );
435 }
436 else
437 {
438 $isEnd = true;
439 }
440 }
441 else
442 {
443 $isEnd = true;
444 }
445
446 if ($isEnd)
447 {
448 if (!empty($actionInfo['next']) && (int)$actionInfo['next'] === 0)
449 {
451
452 foreach ($data[self::PROPERTY_STRUCTURE] as $path)
453 {
454 if (is_string($path) && mb_strpos($path, $fileName) !== false)
455 {
456 try
457 {
458 $content = File::getFileContents($path);
459 $structure->unpackSmallFiles($content);
460 }
461 catch (\Exception $e)
462 {
463 }
464 break;
465 }
466 }
467 }
468 elseif (!empty($actionInfo['next']) && (int)$actionInfo['next'] > 0)
469 {
470 //one more step will load small files
471 $isEnd = false;
472 $next = 0;
473 }
474 }
475
476
477 return [
478 'next' => $next,
479 'finish' => $isEnd,
480 ];
481 }
482
490 public function doStart($app = null, string $mode = Helper::MODE_IMPORT, array $option = []): array
491 {
492 $result = [
493 'finish' => true,
494 ];
495
496 $section = Controller::getEntityCodeList();
497 $result['section'] = array_values($section);
498
499 if (!is_array($app) && $app !== null)
500 {
501 $app = \Bitrix\Rest\AppTable::getByClientId($app);
502 }
503
504 if (is_array($app))
505 {
506 $this->getSetting()->set(Setting::SETTING_APP_INFO, $app);
507 }
508
509 if (!empty($option['UNINSTALL_APP_ON_FINISH']))
510 {
511 $this->getSetting()->set(Setting::SETTING_UNINSTALL_APP_CODE, $option['UNINSTALL_APP_ON_FINISH']);
512 }
513
514 return $result;
515 }
516
525 public function doFinish(string $mode = Helper::MODE_IMPORT)
526 {
527 $result = [
528 'result' => true,
529 'finish' => true,
530 'createItemList' => [],
531 'additional' => [],
532 ];
533
534 $app = $this->getSetting()->get(Setting::SETTING_APP_INFO);
535 if (!empty($app['ID']))
536 {
537 if ($app['INSTALLED'] == AppTable::NOT_INSTALLED)
538 {
540 $updateResult = AppTable::update(
541 $app['ID'],
542 [
543 'INSTALLED' => AppTable::INSTALLED
544 ]
545 );
547 AppTable::install($app['ID']);
549 $result['result'] = $updateResult->isSuccess();
550 }
551 else
552 {
553 $result['result'] = true;
554 }
555 Helper::getInstance()->setBasicApp($this->getManifestCode(), $app['CODE']);
556 }
557 else
558 {
559 Helper::getInstance()->deleteBasicApp($this->getManifestCode());
560 }
561
562 $uninstallAppCode = $this->getSetting()->get(Setting::SETTING_UNINSTALL_APP_CODE);
563 if (!empty($uninstallAppCode))
564 {
565 $res = AppTable::getList(
566 [
567 'filter' => array(
568 "=CODE" => $uninstallAppCode,
569 "!=STATUS" => AppTable::STATUS_LOCAL
570 ),
571 ]
572 );
573 if ($appInfo = $res->fetch())
574 {
575 $clean = true;
576 $checkResult = AppTable::checkUninstallAvailability($appInfo['ID'], $clean);
577 if ($checkResult->isEmpty())
578 {
579 $result['result'] = true;
580 AppTable::uninstall($appInfo['ID'], $clean);
581 $appFields = [
582 'ACTIVE' => 'N',
583 'INSTALLED' => 'N',
584 ];
585 AppTable::update($appInfo['ID'], $appFields);
587 }
588 }
589 }
590
591 $ratio = $this->getSetting()->get(Setting::SETTING_RATIO);
592 $app = $this->getSetting()->get(Setting::SETTING_APP_INFO);
593 $userId = $this->getSetting()->get(Setting::SETTING_USER_ID) ?? 0;
594 $additionalOption = $this->getSetting()->get(Setting::SETTING_ACTION_ADDITIONAL_OPTION);
595 $eventResult = Controller::callEventFinish(
596 [
597 'TYPE' => 'IMPORT',
598 'CONTEXT' => $this->getContextEntity(),
599 'CONTEXT_USER' => $this->getContext(),
600 'RATIO' => $ratio,
601 'MANIFEST_CODE' => $this->getManifestCode(),
602 'IMPORT_MANIFEST' => Manifest::get($this->getManifestCode()) ?? [],
603 'APP_ID' => ($app['ID'] > 0) ? $app['ID'] : 0,
604 'USER_ID' => $userId,
605 'ADDITIONAL_OPTION' => $additionalOption,
606 ]
607 );
608
609 foreach ($eventResult as $data)
610 {
611 if (is_array($data['CREATE_DOM_LIST']))
612 {
613 $result['createItemList'] = array_merge($result['createItemList'], $data['CREATE_DOM_LIST']);
614 }
615
616 if (is_array($data['ADDITIONAL']))
617 {
618 $result['additional'] = array_merge($result['additional'], $data['ADDITIONAL']);
619 }
620 }
621 $result['finish'] = $result['result'];
622
623 return $result;
624 }
625
626 protected function checkRegister($data): array
627 {
628 $result = [];
629
630 if (
631 !isset($data['MANIFEST']['CODE'])
632 || !Manifest::isRestImportAvailable($data['MANIFEST']['CODE'])
633 )
634 {
635 $result = [
636 'error' => static::ERROR_MANIFEST_IS_NOT_AVAILABLE,
637 'error_description' => 'Manifest is not available.',
638 ];
639 }
640
641 return $result;
642 }
643
649 public function get(): array
650 {
651 $status = $this->getStatus();
652 $result = parent::get();
653 $actionInfo = $this->getSetting()->get(Setting::SETTING_ACTION_INFO);
654 if ($status === self::STATUS_PROCESS || $status === self::STATUS_ERROR)
655 {
656 if ($actionInfo)
657 {
658 $result['progress'] = [
659 'action' => $actionInfo['run'],
660 'step' => $actionInfo['step'],
661 ];
662 if (
663 !empty($actionInfo['section'][$actionInfo['currentSection']])
664 && !empty($actionInfo['run'])
665 && $actionInfo['run'] !== self::STEP_FINISH
666 )
667 {
668 $result['progress']['section'] = $actionInfo['section'][$actionInfo['currentSection']];
669 }
670 }
671 }
672 elseif ($status === self::STATUS_FINISH)
673 {
674 $result['additional'] = $actionInfo['setting']['additional'] ?? [];
675 $result['createItemList'] = $actionInfo['setting']['createItemList'] ?? [];
676 }
677
678 return $result;
679 }
680}
static getMessage($code, $replace=null, $language=null)
Definition loc.php:29
static log($appId, $action)
Definition applog.php:90
static install($appId)
Definition app.php:459
const STATUS_LOCAL
Definition app.php:74
static uninstall($appId, $clean=0)
Definition app.php:513
const NOT_INSTALLED
Definition app.php:63
static setSkipRemoteUpdate($v)
Definition app.php:236
doClean($code, $step, $next, bool $clearFull=false)
Definition import.php:320
doLoad($step, $code, $content)
Definition import.php:362
doInitManifest(?string $next, int $step, string $type)
Definition import.php:281
doStart($app=null, string $mode=Helper::MODE_IMPORT, array $option=[])
Definition import.php:490
doFinish(string $mode=Helper::MODE_IMPORT)
Definition import.php:525
static callEventInit($code, $params=[])
Definition manifest.php:37
static isRestImportAvailable(string $entityCode)
Definition manifest.php:187