Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
phraseindexcollection.php
1<?php
2
4
9
10
15 extends Index\Internals\EO_PhraseIndex_Collection
16{
20 public static bool $verbose = false;
21
29 public function countItemsToProcess(?Translate\Filter $filter = null): int
30 {
31 if (isset($filter, $filter->path))
32 {
33 $relPath = '/'. \trim($filter->path, '/');
34 $relPath = Translate\IO\Path::replaceLangId($relPath, '#LANG_ID#');
35
36 $topPathRes = Index\Internals\PathIndexTable::getList([
37 'select' => ['ID'],
38 'filter' => ['=PATH' => $relPath]
39 ]);
40 if (!($topPath = $topPathRes->fetch()))
41 {
42 return 0;
43 }
44
45 $checkLanguages = Translate\Config::getEnabledLanguages();
46 if (isset($filter, $filter->langId))
47 {
48 $checkLanguages = \array_intersect($filter->langId, $checkLanguages);
49 }
50
51 $fileFilter = [
52 '=PATH.DESCENDANTS.PARENT_ID' => $topPath['ID'],//ancestor
53 '=LANG_ID' => $checkLanguages,
54 //todo: add filter by INDEXED_TIME
55 ];
56 $totalItems = (int)Index\Internals\FileIndexTable::getCount($fileFilter);
57 }
58 else
59 {
60 $totalItems = (int)Index\Internals\FileIndexTable::getCount();
61 }
62
63 return $totalItems;
64 }
65
66
76 public function collect(?Translate\Filter $filter = null, ?Translate\Controller\ITimeLimit $timer = null, ?Translate\Filter $seek = null): int
77 {
78 if (isset($filter, $filter->path))
79 {
80 $relPath = $filter->path;
81 }
82 else
83 {
84 $relPath = Translate\Config::getDefaultPath();
85 }
86
87 $relPath = '/'. \trim($relPath, '/');
88 $relPath = Translate\IO\Path::replaceLangId($relPath, '#LANG_ID#');
89
90 $checkLanguages = Translate\Config::getEnabledLanguages();
91 if (isset($filter, $filter->langId))
92 {
93 $checkLanguages = \array_intersect($filter->langId, $checkLanguages);
94 }
95
96 $topPathRes = Index\Internals\PathIndexTable::getList([
97 'select' => ['ID'],
98 'filter' => ['=PATH' => $relPath]
99 ]);
100 if (!($topPath = $topPathRes->fetch()))
101 {
102 return 0;
103 }
104
105 $fileFilter = [
106 '=PATH.DESCENDANTS.PARENT_ID' => $topPath['ID'],//ancestor
107 '=LANG_ID' => $checkLanguages,
108 //todo: add filter by INDEXED_TIME
109 ];
110 if (isset($seek, $seek->pathId))
111 {
112 $fileFilter['>PATH_ID'] = $seek->pathId;
113 }
114
115 Main\Application::getConnection()->queryExecute("SET SESSION group_concat_max_len = 100000");
116
117 $fileListQuery = Index\Internals\FileIndexTable::query();
118
119 $fileListQuery
120 ->addSelect('PATH_ID')
121
122 ->registerRuntimeField(new ExpressionField('FILE_IDS', "GROUP_CONCAT(%s ORDER BY (%s) SEPARATOR '\\n')", ['ID', 'ID']))
123 ->addSelect('FILE_IDS')
124
125 ->registerRuntimeField(new ExpressionField('LANG_IDS', "GROUP_CONCAT(%s ORDER BY (%s) SEPARATOR '\\n')", ['LANG_ID', 'ID']))
126 ->addSelect('LANG_IDS')
127
128 ->registerRuntimeField(new ExpressionField('FULL_PATHS', "GROUP_CONCAT(%s ORDER BY (%s) SEPARATOR '\\n')", ['FULL_PATH', 'ID']))
129 ->addSelect('FULL_PATHS')
130
131 ->setFilter($fileFilter)
132 ->setOrder(['PATH_ID' => 'ASC'])
133 ->addGroup('PATH_ID')
134 ;
135
136 $fileListRes = $fileListQuery->exec();
137
138 $phraseId = Index\Internals\PhraseIndexTable::query()
139 ->registerRuntimeField(new ExpressionField('MAXID', 'MAX(%s)', ['ID']))
140 ->addSelect('MAXID')
141 ->exec()
142 ->fetch()['MAXID'];
143
144 $processedItemCount = 0;
145
146 while (true)
147 {
148 $lastPathId = null;
149 $filePortion = [];
150 while ($pathRow = $fileListRes->fetch())
151 {
152 $filePortion[] = $pathRow;
153 if (\count($filePortion) >= 5)
154 {
155 break;
156 }
157 }
158 if (empty($filePortion))
159 {
160 break;
161 }
162
163 $fileData = [];
164 $phraseCodeData = [];
165 $phraseData = [];
166 $pathIdPortion = [];
167 $nonexistentFiles = [];
168
169 foreach ($filePortion as $indexFile)
170 {
171 $pathId = (int)$indexFile['PATH_ID'];
172 $pathIdPortion[] = $lastPathId = $pathId;
173
174 $fileIds = [];
175 foreach (\explode("\n", $indexFile['FILE_IDS']) as $v)
176 {
177 $fileIds[] = (int)$v;
178 }
179
180 $langIds = [];
181 foreach (\explode("\n", $indexFile['LANG_IDS']) as $v)
182 {
183 $langIds[] = \trim($v);
184 }
185
186 $filePaths = [];
187 foreach (\explode("\n", $indexFile['FULL_PATHS']) as $v)
188 {
189 $filePaths[] = \trim($v);
190 }
191
192 foreach ($fileIds as $inx => $indexFileId)
193 {
194 $langId = $langIds[$inx];
195 $fullPath = $filePaths[$inx];
196
197 if (self::$verbose)
198 {
199 echo "Lang file: {$fullPath}\n";
200 }
201
202 $current = new Translate\File($fullPath);
203 $current->setLangId($langId);
204 if (!$current->load())
205 {
206 $nonexistentFiles[] = $indexFileId;
207 continue;
208 }
209
210 $fileData[] = [
211 'ID' => $indexFileId,
212 'PATH_ID' => $pathId,
213 'LANG_ID' => $langId,
214 'PHRASE_COUNT' => $current->count(),
215 'FULL_PATH' => $current->getPath(),
216 'INDEXED' => 'Y',
217 'INDEXED_TIME' => new Main\Type\DateTime(),
218 ];
219
220 foreach ($current as $code => $phrase)
221 {
222 $phraseId ++;
223 $phraseCodeData[] = [
224 'ID' => $phraseId,
225 'FILE_ID' => $indexFileId,
226 'PATH_ID' => $pathId,
227 'LANG_ID' => $langId,
228 'CODE' => $code,
229 ];
230 if (!isset($phraseData[$langId]))
231 {
232 $phraseData[$langId] = [];
233 }
234 $phraseData[$langId][] = [
235 'ID' => $phraseId,
236 'FILE_ID' => $indexFileId,
237 'PATH_ID' => $pathId,
238 'CODE' => $code,
239 'PHRASE' => $phrase,
240 ];
241 }
242 }
243
244 $processedItemCount += \count($fileIds);
245 }
246
247 // delete
248 Index\Internals\PhraseIndexTable::bulkDelete([
249 '=PATH_ID' => $pathIdPortion,
250 '=LANG_ID' => $checkLanguages,
251 ]);
252
253 if (\count($nonexistentFiles) > 0)
254 {
255 Index\Internals\PhraseIndexTable::bulkDelete(['=FILE_ID' => $nonexistentFiles]);
256 Index\Internals\FileIndexTable::bulkDelete(['=ID' => $nonexistentFiles]);
257 foreach (Translate\Config::getEnabledLanguages() as $langId)
258 {
259 $ftsClass = Index\Internals\PhraseFts::getFtsEntityClass($langId);
260 $ftsClass::bulkDelete(['=FILE_ID' => $nonexistentFiles]);
261 }
262 }
263
264 // Add
265 if (\count($phraseCodeData) > 0)
266 {
267 Index\Internals\FileIndexTable::bulkAdd($fileData, 'ID');
268 Index\Internals\PhraseIndexTable::bulkAdd($phraseCodeData);
269 foreach ($phraseData as $langId => $phraseLangData)
270 {
271 $ftsClass = Index\Internals\PhraseFts::getFtsEntityClass($langId);
272 $ftsClass::bulkAdd($phraseLangData, 'ID');
273 }
274 }
275
276 Index\Internals\PathIndexTable::bulkUpdate(
277 ['INDEXED' => 'Y', 'INDEXED_TIME' => new Main\Type\DateTime()],
278 ['=ID' => $pathIdPortion]
279 );
280
281 if ($timer !== null && $timer->hasTimeLimitReached())
282 {
283 if ($seek !== null)
284 {
285 $seek->nextPathId = $lastPathId;
286 }
287 break;
288 }
289 }
290
291
292 if ($timer === null || !$timer->hasTimeLimitReached())
293 {
294 Index\Internals\PathIndexTable::bulkUpdate(
295 ['INDEXED' => 'Y', 'INDEXED_TIME' => new Main\Type\DateTime()],
296 [
297 '=IS_DIR' => 'Y',
298 '=DESCENDANTS.PARENT_ID' => $topPath['ID'],//ancestor
299 ]
300 );
301 }
302
303 return $processedItemCount;
304 }
305
306
314 public function purge(?Translate\Filter $filter = null): self
315 {
316 Index\Internals\PhraseIndexTable::purge($filter);
317
318 return $this;
319 }
320
328 public function getPhraseByCode($code): ?string
329 {
330 foreach ($this as $phrase)
331 {
332 if ($phrase->getCode() === $code)
333 {
334 return $phrase;
335 }
336 }
337
338 return null;
339 }
340}
341
countItemsToProcess(?Translate\Filter $filter=null)
collect(?Translate\Filter $filter=null, ?Translate\Controller\ITimeLimit $timer=null, ?Translate\Filter $seek=null)