13 extends Index\Internals\EO_PathIndex_Collection
19 private static $documentRoot;
22 private static $enabledLanguages;
24 private static $availableLanguages;
27 private static $useTranslationRepository;
29 private static $translationRepositoryLanguages;
31 private static $translationEnabledLanguages;
33 private static $translationRepositoryRoot;
36 private $immediateChildren = [];
39 private $ancestorsPaths = [];
42 private $checkLanguages = [];
49 private static function configure()
53 self::$enabledLanguages = Translate\Config::getEnabledLanguages();
54 self::$availableLanguages = Translate\Config::getAvailableLanguages();
56 self::$useTranslationRepository = Main\Localization\Translation::useTranslationRepository();
57 if (self::$useTranslationRepository)
59 self::$translationRepositoryLanguages = Translate\Config::getTranslationRepositoryLanguages();
63 self::$translationEnabledLanguages = \array_intersect(self::$translationRepositoryLanguages, self::$enabledLanguages);
76 if (isset($filter, $filter->path))
78 $relPath =
'/'. \trim($filter->path,
'/');
79 $totalItems = (int)Index\Internals\PathLangTable::getCount([
'=%PATH' => $relPath .
'%']);
83 $totalItems = (int)Index\Internals\PathLangTable::getCount();
102 if (isset($filter, $filter->path))
104 $relPath = $filter->path;
108 $relPath = Translate\Config::getDefaultPath();
110 $relPath =
'/'. \trim($relPath,
'/');
112 if (self::$useTranslationRepository)
114 $this->checkLanguages = self::$translationEnabledLanguages;
115 if (isset($filter, $filter->langId))
117 $this->checkLanguages = \array_intersect($filter->langId, $this->checkLanguages);
122 '=%PATH' => $relPath.
'%'
124 if (isset($seek, $seek->pathLangId))
126 $pathFilter[
'>ID'] = $seek->pathLangId;
129 $cachePathLangRes = Index\Internals\PathLangTable::getList([
130 'filter' => $pathFilter,
131 'order' => [
'ID' =>
'ASC'],
132 'select' => [
'ID',
'PATH'],
134 $processedItemCount = 0;
135 while ($pathLang = $cachePathLangRes->fetch())
137 $this->collectFilePath($pathLang[
'PATH']);
139 $processedItemCount ++;
141 if ($timer !==
null && $timer->hasTimeLimitReached())
145 $seek->nextLangPathId = (int)$pathLang[
'ID'];
151 return $processedItemCount;
161 private function collectFilePath($relPath): int
163 $fullPath = Translate\IO\Path::tidy(self::$documentRoot.
'/'.$relPath);
167 $topPathId = (int)$topPath[
'ID'];
168 $topDepthLevel = (int)$topPath[
'DEPTH_LEVEL'];
169 $isTopLang = $topPath[
'IS_LANG'];
174 $topLangId = Translate\IO\Path::extractLangId($relPath);
177 $relPath = Translate\IO\Path::replaceLangId($relPath,
'#LANG_ID#');
183 if (!$langSettings->isExists() || !$langSettings->load())
185 unset($langSettings);
200 $lookForLangDirectory =
205 $isParentLang =
false,
206 $parentLangId =
null,
210 &$lookForLangDirectory,
215 $processedItemCount = 0;
217 $this->getImmediateChildren($parentId);
221 $childrenList = Translate\IO\FileSystemHelper::getFileList($parentFullPath);
222 if (!empty($childrenList))
224 foreach ($childrenList as $fullPath)
226 $name = \basename($fullPath);
227 if (\in_array($name, Translate\IGNORE_FS_NAMES))
231 if (!Translate\
IO\Path::isPhpFile($name))
235 if (!\is_file($fullPath))
240 $relPath = Translate\IO\Path::replaceLangId($parentRelPath .
'/'. $name,
'#LANG_ID#');
244 if (isset($this->immediateChildren[$parentId][$relPath]))
246 $pathId = $this->immediateChildren[$parentId][$relPath];
251 echo
"File path: {$relPath}";
253 if ($pathId ===
null)
256 'PARENT_ID' => $parentId,
261 'DEPTH_LEVEL' => $depthLevel,
264 if ($langSettings instanceof Translate\Settings)
266 $settings = $langSettings->getOptions($relPath);
273 $res = Index\Internals\PathIndexTable::add($nodeData);
274 $pathId = $res->getId();
276 $this->immediateChildren[$parentId][$relPath] = $pathId;
281 echo
"\tIndex id: {$pathId}\n";
285 $processedItemCount ++;
291 $childrenList = Translate\IO\FileSystemHelper::getFolderList($parentFullPath);
292 if (empty($childrenList))
297 if ($parentLangId ===
null && \basename($parentFullPath) ===
'lang')
299 foreach ($childrenList as $i => $fullPath)
301 $name = \basename($fullPath);
302 if (\in_array($name, Translate\IGNORE_FS_NAMES))
304 unset($childrenList[$i]);
306 if (!\in_array($name, self::$enabledLanguages))
308 unset($childrenList[$i]);
311 unset($i, $fullPath, $name);
312 if (self::$useTranslationRepository)
315 foreach ($this->checkLanguages as $langId)
317 $fullPathLang = Main\Localization\Translation::convertLangPath($parentFullPath.
'/'.$langId, $langId);
318 if (\file_exists($fullPathLang))
320 $childrenList[] = $fullPathLang;
323 unset($langId, $fullPathLang);
327 if (!empty($childrenList))
329 $ignoreDev = \implode(
'|', Translate\IGNORE_MODULE_NAMES);
330 foreach ($childrenList as $fullPath)
332 $name = \basename($fullPath);
333 if (\in_array($name, Translate\IGNORE_FS_NAMES))
338 $relPath = $parentRelPath .
'/'. $name;
340 if (!\is_dir($fullPath))
345 if (\in_array($relPath, Translate\IGNORE_BX_NAMES))
351 if (\preg_match(
"#^bitrix/modules/[^/]+/({$ignoreDev})$#", \trim($relPath,
'/')))
356 if ($isParentLang && \in_array($name, Translate\IGNORE_LANG_NAMES))
361 $isLang = $isParentLang || ($name ===
'lang');
364 if (\in_array($name, self::$availableLanguages))
367 if (!\in_array($name, self::$enabledLanguages))
371 $parentLangId = $name;
374 $relPath = Translate\IO\Path::replaceLangId($relPath,
'#LANG_ID#');
379 if (isset($this->immediateChildren[$parentId][$relPath]))
381 $pathId = $this->immediateChildren[$parentId][$relPath];
386 echo
"Path folder: {$relPath}";
388 if ($pathId ===
null)
391 'PARENT_ID' => $parentId,
394 'IS_LANG' => $isLang ?
'Y' :
'N',
396 'DEPTH_LEVEL' => $depthLevel,
399 if ($langSettings instanceof Translate\Settings)
401 $settings = $langSettings->getOptions($relPath);
408 $res = Index\Internals\PathIndexTable::add($nodeData);
409 $pathId = $res->getId();
411 $this->immediateChildren[$parentId][$relPath] = $pathId;
412 $this->immediateChildren[$pathId] = [];
414 $this->ancestorsPaths[$relPath] = [
416 'DEPTH_LEVEL' => $depthLevel,
417 'IS_LANG' => $isLang,
424 echo
"\tIndex id: {$pathId}\n";
427 $processedItemCount += $lookForLangDirectory($fullPath, $relPath, $pathId, $isLang, $parentLangId, $depthLevel + 1);
428 $processedItemCount ++;
432 return $processedItemCount;
435 $processedItemCount = $lookForLangDirectory($fullPath, $relPath, $topPathId, $isTopLang, $topLangId, $topDepthLevel + 1);
437 if ($isTopLang && isset($langSettings))
440 $settings = $langSettings->getOptions(
'*');
443 Index\Internals\PathIndexTable::bulkUpdate(
448 '=%PATH' => $relPath.
'/%',
452 foreach ($langSettings as $settingPath => $settings)
454 if (\strpos($settingPath,
'*') !==
false && $settingPath !==
'*' && !empty($settings[
'languages']))
456 $settingPath = \str_replace(
'*',
'', $settingPath);
457 Index\Internals\PathIndexTable::bulkUpdate(
461 '=PATH' => $relPath .
'/#LANG_ID#/'. $settingPath,
462 '=%PATH' => $relPath .
'/#LANG_ID#/'. $settingPath.
'/%',
467 foreach ($langSettings as $settingPath => $settings)
471 Index\Internals\PathIndexTable::bulkUpdate(
473 [
'=PATH' => $relPath .
'/#LANG_ID#/'. $settingPath]
479 return $processedItemCount;
493 if (isset($this->ancestorsPaths[$path]))
495 return $this->ancestorsPaths[$path];
498 $pathParts = \explode(
'/', \trim($path,
'/'));
501 $ancestorsPathSearch = [];
502 foreach ($pathParts as $part)
504 $searchPath .=
'/'. $part;
505 if (isset($this->ancestorsPaths[$searchPath]))
509 $ancestorsPathSearch[] = $searchPath;
511 $pathRes = Index\Internals\PathIndexTable::getList([
512 'select' => [
'ID',
'DEPTH_LEVEL',
'IS_LANG',
'PATH'],
513 'filter' => [
'=PATH' => $ancestorsPathSearch],
515 while ($pathInx = $pathRes->fetch())
517 $pathInx[
'IS_LANG'] = ($pathInx[
'IS_LANG'] ==
'Y');
518 $this->ancestorsPaths[$pathInx[
'PATH']] = $pathInx;
521 if (isset($this->ancestorsPaths[$path]))
523 return $this->ancestorsPaths[$path];
530 $searchDepthLevel = 0;
533 foreach ($pathParts as $part)
535 $searchPath .=
'/'. $part;
537 if (isset($this->ancestorsPaths[$searchPath]) && $searchPath !== $path)
539 $searchParentId = (int)$this->ancestorsPaths[$searchPath][
'ID'];
540 $searchDepthLevel = (int)$this->ancestorsPaths[$searchPath][
'DEPTH_LEVEL'] + 1;
541 $isLang = $this->ancestorsPaths[$searchPath][
'IS_LANG'];
545 if ($isLang ===
false)
547 $isLang = ($part ===
'lang');
552 'PATH' => $searchPath,
553 'PARENT_ID' => $searchParentId,
554 'DEPTH_LEVEL' => $searchDepthLevel,
555 'IS_LANG' => $isLang ?
'Y' :
'N',
556 'IS_DIR' => (Translate\IO\Path::isPhpFile($part) ?
'N' :
'Y'),
559 $pathInx = Index\Internals\PathIndexTable::add($nodeData);
560 $searchParentId = $pathInx->getId();
562 $this->ancestorsPaths[$searchPath] = [
563 'ID' => $searchParentId,
564 'DEPTH_LEVEL' => $searchDepthLevel,
565 'IS_LANG' => $isLang,
566 'PATH' => $searchPath,
569 $searchDepthLevel ++;
572 return $this->ancestorsPaths[$path];
583 private function getImmediateChildren($parentId): array
585 if (!isset($this->immediateChildren[$parentId]))
587 $this->immediateChildren[$parentId] = [];
589 $nodeRes = Index\Internals\PathIndexTable::getList([
590 'filter' => [
'=PARENT_ID' => $parentId],
591 'select' => [
'ID',
'PATH'],
593 while ($nodeInx = $nodeRes->fetch())
595 $this->immediateChildren[$parentId][$nodeInx[
'PATH']] = (int)$nodeInx[
'ID'];
599 return $this->immediateChildren[$parentId];
611 private function getAncestors($nodeId, $topNodeId = -1): array
613 $nodeRes = Index\Internals\PathIndexTable::getList([
614 'filter' => [
'=ID' => (
int)$nodeId],
618 if ($nodeInx = $nodeRes->fetchObject())
620 $result[$nodeInx->getId()] = $nodeInx;
622 if ((
int)$nodeInx->getParentId() > 0)
624 $nodeRes = Index\Internals\PathIndexTable::getList([
626 '=DESCENDANTS.PARENT_ID' => $nodeInx->getId(),
628 'order' => [
'DESCENDANTS.DEPTH_LEVEL' =>
'DESC'],
630 while ($nodeInx = $nodeRes->fetchObject())
632 $result[$nodeInx->getId()] = $nodeInx;
634 if ((
int)$nodeInx->getParentId() == 0)
638 if ($topNodeId > 0 && (
int)$nodeInx->getId() == $topNodeId)
646 return \array_reverse($result,
true);
656 $pathList = Index\Internals\PathIndexTable::getList([
664 while ($path = $pathList->fetch())
666 Index\Internals\PathIndexTable::arrangeTree($path[
'ID']);
681 Index\Internals\PathIndexTable::purge($filter);
694 public function validate(?Translate\
Filter $filter =
null,
bool $recursively =
true): self
700 $filterOut = Index\Internals\FileIndexTable::processFilter($filter);
701 Index\Internals\FileIndexTable::bulkUpdate($update, $filterOut);
704 $filterOut = Index\Internals\PathIndexTable::processFilter($filter);
705 Index\Internals\PathIndexTable::bulkUpdate($update, $filterOut);
718 public function unvalidate(Translate\
Filter $filter =
null,
bool $recursively =
true): self
722 $filterOut = Index\Internals\FileIndexTable::processFilter($filter);
723 Index\Internals\FileIndexTable::bulkUpdate([
'INDEXED' =>
'N'], $filterOut);
726 $filterOut = Index\Internals\PathIndexTable::processFilter($filter);
727 Index\Internals\PathIndexTable::bulkUpdate([
'INDEXED' =>
'N'], $filterOut);
742 $searchPath = isset($filter, $filter->path) ? $filter->path :
'';
744 if (!empty($searchPath))
746 $pathStartRes = Index\Internals\PathIndexTable::getList([
748 '=PATH' => $searchPath,
750 'select' => [
'ID',
'PATH'],
752 if ($path = $pathStartRes->fetchObject())
754 $relPathParts = \explode(
'/', \trim($path->getPath(),
'/'));
757 if (\count($relPathParts) >= 3 && $relPathParts[0] ==
'bitrix' && $relPathParts[1] ==
'modules')
759 $moduleId = $path->detectModuleId();
760 if ($moduleId !==
null)
762 Index\Internals\PathIndexTable::bulkUpdate(
763 [
'MODULE_ID' => $moduleId],
764 [
'=DESCENDANTS.PARENT_ID' => $path->getId()]
775 $pathModulesRes = Index\Internals\PathIndexTable::getList([
777 '=PATH' =>
'/bitrix/modules',
781 while ($pathModules = $pathModulesRes->fetch())
783 $pathList = Index\Internals\PathIndexTable::getList([
785 '=PARENT_ID' => $pathModules[
'ID'],
787 'select' => [
'ID',
'PATH'],
789 while ($path = $pathList->fetchObject())
791 $moduleId = $path->detectModuleId();
792 if ($moduleId !==
null)
794 Index\Internals\PathIndexTable::bulkUpdate(
795 [
'MODULE_ID' => $moduleId],
796 [
'=DESCENDANTS.PARENT_ID' => $path->getId()]
816 foreach (Translate\ASSIGNMENT_TYPES as $assignmentId)
818 $pathEntryRes = Index\Internals\PathIndexTable::getList([
820 '=PATH' =>
'/bitrix/'. $assignmentId,
822 'select' => [
'ID',
'PATH'],
824 while ($path = $pathEntryRes->fetchObject())
826 Index\Internals\PathIndexTable::bulkUpdate(
827 [
'ASSIGNMENT' => $assignmentId],
828 [
'=DESCENDANTS.PARENT_ID' => $path->getId()]
833 $pathModulesRes = Index\Internals\PathIndexTable::getList([
835 '=PATH' =>
'/bitrix/modules',
839 while ($pathModules = $pathModulesRes->fetch())
841 $pathList = Index\Internals\PathIndexTable::getList([
843 '=PARENT_ID' => $pathModules[
'ID'],
844 '!=MODULE_ID' =>
null,
846 'select' => [
'ID',
'PATH',
'MODULE_ID'],
848 while ($modulePath = $pathList->fetchObject())
850 $moduleId = $modulePath->getModuleId();
852 foreach (Translate\ASSIGNMENT_TYPES as $assignmentId)
856 '/bitrix/modules/'.$moduleId.
'/install/'. $assignmentId,
858 '/bitrix/modules/'.$moduleId.
'/lang/#LANG_ID#/'. $assignmentId,
860 '/bitrix/modules/'.$moduleId.
'/lang/#LANG_ID#/install/'. $assignmentId,
862 '/bitrix/modules/'.$moduleId.
'/install/bitrix/'. $assignmentId,
865 '/bitrix/modules/'.$moduleId.
'/handlers/'. $assignmentId,
867 if ($assignmentId ==
'templates')
870 $filterPaths[] =
'/bitrix/modules/'.$moduleId.
'/install/public/'. $assignmentId;
872 $pathEntryRes = Index\Internals\PathIndexTable::getList([
874 '=PATH' => $filterPaths,
875 '=DESCENDANTS.PARENT_ID' => $modulePath->getId(),
877 'select' => [
'ID',
'PATH'],
879 while ($path = $pathEntryRes->fetchObject())
881 Index\Internals\PathIndexTable::bulkUpdate(
882 [
'ASSIGNMENT' => $assignmentId],
883 [
'=DESCENDANTS.PARENT_ID' => $path->getId()]