Completed
Push — master ( b3735d...6e77c8 )
by Maxence
03:11 queued 01:13
created

Live::onNewAction()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 12

Duplication

Lines 12
Ratio 100 %

Importance

Changes 0
Metric Value
dl 12
loc 12
rs 9.8666
c 0
b 0
f 0
cc 3
nc 2
nop 1
1
<?php
2
/**
3
 * FullTextSearch - Full text search framework for Nextcloud
4
 *
5
 * This file is licensed under the Affero General Public License version 3 or
6
 * later. See the COPYING file.
7
 *
8
 * @author Maxence Lange <[email protected]>
9
 * @copyright 2018
10
 * @license GNU AGPL version 3 or any later version
11
 *
12
 * This program is free software: you can redistribute it and/or modify
13
 * it under the terms of the GNU Affero General Public License as
14
 * published by the Free Software Foundation, either version 3 of the
15
 * License, or (at your option) any later version.
16
 *
17
 * This program is distributed in the hope that it will be useful,
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
 * GNU Affero General Public License for more details.
21
 *
22
 * You should have received a copy of the GNU Affero General Public License
23
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
24
 *
25
 */
26
27
namespace OCA\FullTextSearch\Command;
28
29
use Exception;
30
use OCA\FullTextSearch\Exceptions\InterruptException;
31
use OCA\FullTextSearch\Exceptions\TickDoesNotExistException;
32
use OCA\FullTextSearch\Model\ExtendedBase;
33
use OCA\FullTextSearch\Model\Runner;
34
use OCA\FullTextSearch\Model\Index as ModelIndex;
35
use OCA\FullTextSearch\Service\CliService;
36
use OCA\FullTextSearch\Service\ConfigService;
37
use OCA\FullTextSearch\Service\IndexService;
38
use OCA\FullTextSearch\Service\MiscService;
39
use OCA\FullTextSearch\Service\PlatformService;
40
use OCA\FullTextSearch\Service\ProviderService;
41
use OCA\FullTextSearch\Service\RunningService;
42
use OCP\IUserManager;
43
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
44
use Symfony\Component\Console\Input\InputInterface;
45
use Symfony\Component\Console\Output\OutputInterface;
46
use Symfony\Component\Console\Terminal;
47
48
49
class Live extends ExtendedBase {
50
51
	const CYCLE_DELAY = 10;
52
53
	const PANEL_RUN = 'run';
54
	const PANEL_RUN_LINE_MEMORY = 'Memory: %_memory%';
55
56
	const PANEL_INDEX = 'indexing';
57
	const PANEL_INDEX_LINE_HEADER = '┌─ Indexing %_paused% ────';
58
	const PANEL_INDEX_LINE_ACCOUNT = '│ Provider: <info>%providerName:-20s%</info> Account: <info>%userId%</info>';
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 100 characters; contains 112 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
59
	const PANEL_INDEX_LINE_ACTION = '│ Action: <info>%action%</info>';
60
	const PANEL_INDEX_LINE_DOCUMENT = '│ Document: <info>%documentId%</info>';
61
	const PANEL_INDEX_LINE_INFO = '│ Info: <info>%info%</info>';
62
	const PANEL_INDEX_LINE_TITLE = '│ Title: <info>%title%</info>';
63
	const PANEL_INDEX_LINE_CONTENT = '│ Content size: <info>%content%</info>';
64
	const PANEL_INDEX_LINE_RESULT = '│ Result: %resultColored%';
65
	const PANEL_INDEX_LINE_FOOTER = '└──';
66
67
	const PANEL_STATUS = 'status';
68
	const PANEL_STATUS_LINE_HEADER = '┌─ Status ────';
69
	const PANEL_STATUS_LINE_DOCUMENTS = '│ Progress: %documentLeft:6s%/%documentTotal%   %progressStatus%';
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 100 characters; contains 104 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
70
//	const PANEL_STATUS_LINE_DOCUMENTS_LEFT = '│ Document left:';
71
	const PANEL_STATUS_LINE_ERRORS = '│ Error: <comment>%errorCurrent:6s%</comment>/<comment>%errorTotal%</comment>';
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 100 characters; contains 114 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
72
	const PANEL_STATUS_LINE_ERROR_EXCEPTION = '│ Exception: <comment>%errorException%</comment>';
73
	const PANEL_STATUS_LINE_ERROR_MESSAGE1 = '│ Message: <comment>%errorMessageA%</comment>';
74
	const PANEL_STATUS_LINE_ERROR_MESSAGE2 = '│ <comment>%errorMessageB%</comment>';
75
	const PANEL_STATUS_LINE_ERROR_MESSAGE3 = '│ <comment>%errorMessageC%</comment>';
76
	const PANEL_STATUS_LINE_ERROR_INDEX = '│ Index: <comment>%errorIndex%</comment>';
77
78
79
	const PANEL_STATUS_LINE_FOOTER = '└──';
80
81
	const PANEL_LINE_EMPTY = '│ ';
82
83
	const PANEL_COMMANDS_ROOT = 'root';
84
	const PANEL_COMMANDS_ROOT_LINE = '## <char>q</char>:quit ## <char>p</char>:pause ';
85
	const PANEL_COMMANDS_PAUSED = 'paused';
86
	const PANEL_COMMANDS_PAUSED_LINE = '## <char>q</char>:quit ## <char>u</char>:unpause ## <char>n</char>:next step';
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 100 characters; contains 115 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
87
	const PANEL_COMMANDS_DONE = 'done';
88
	const PANEL_COMMANDS_DONE_LINE = '## <char>q</char>:quit';
89
	const PANEL_COMMANDS_ERRORS = 'errors';
90
	const PANEL_COMMANDS_ERRORS_LINE = '## <char>f</char>:first error ## <char>h</char>/<char>j</char>:prec/next error ## <char>d</char>:delete error ## <char>l</char>:last error';
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 100 characters; contains 177 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
91
92
93
	/** @var IUserManager */
94
	private $userManager;
95
96
	/** @var ConfigService */
97
	private $configService;
98
99
	/** @var CliService */
100
	private $cliService;
101
102
	/** @var RunningService */
103
	private $runningService;
104
105
	/** @var IndexService */
106
	private $indexService;
107
108
	/** @var PlatformService */
109
	private $platformService;
110
111
	/** @var ProviderService */
112
	private $providerService;
113
114
	/** @var MiscService */
115
	private $miscService;
116
117
118
	/** @var Runner */
119
	private $runner;
120
121
	/** @var Terminal */
122
	private $terminal;
123
124
	/** @var array */
125
	private $errors = [];
126
127
	/** @var bool */
128
	private $navigateLastError = true;
129
130
131
	/**
132
	 * Live constructor.
133
	 *
134
	 * @param IUserManager $userManager
135
	 * @param RunningService $runningService
136
	 * @param ConfigService $configService
137
	 * @param IndexService $indexService
138
	 * @param PlatformService $platformService
139
	 * @param ProviderService $providerService
140
	 * @param MiscService $miscService
141
	 */
142
	public function __construct(
143
		IUserManager $userManager, RunningService $runningService, ConfigService $configService,
144
		CliService $cliService, IndexService $indexService, PlatformService $platformService,
145
		ProviderService $providerService, MiscService $miscService
146
	) {
147
		parent::__construct();
148
		$this->userManager = $userManager;
149
150
		$this->runner = new Runner($runningService, 'commandLive');
151
		$this->configService = $configService;
152
		$this->cliService = $cliService;
153
		$this->runningService = $runningService;
154
		$this->indexService = $indexService;
155
		$this->platformService = $platformService;
156
		$this->providerService = $providerService;
157
		$this->miscService = $miscService;
158
	}
159
160
161
	/**
162
	 *
163
	 */
164
	protected function configure() {
165
		parent::configure();
166
		$this->setName('fulltextsearch:live')
167
			 ->setDescription('Index files');
168
	}
169
170
171
	/**
172
	 * @param InputInterface $input
173
	 * @param OutputInterface $output
174
	 *
175
	 * @return int|null|void
176
	 * @throws Exception
177
	 */
178
	protected function execute(InputInterface $input, OutputInterface $output) {
179
180
		if ($this->configService->getCloudVersion() < 14) {
181
			throw new Exception('This feature is only available on Nextcloud 14 or newer');
182
		}
183
184
		/** do not get stuck while waiting interactive input */
185
		readline_callback_handler_install(
186
			'', function() {
187
		}
188
		);
189
		stream_set_blocking(STDIN, false);
190
191
		$this->terminal = new Terminal();
192
193
		$outputStyle = new OutputFormatterStyle('white', 'black', ['bold']);
194
		$output->getFormatter()
195
			   ->setStyle('char', $outputStyle);
196
197
		$this->runner = new Runner($this->runningService, 'commandIndex', ['nextStep' => 'n']);
198
		$this->runner->onKeyPress([$this, 'onKeyPressed']);
199
		$this->runner->onNewAction([$this, 'onNewAction']);
200
		$this->runner->onNewIndexError([$this, 'onNewIndexError']);
201
202
		$this->indexService->setRunner($this->runner);
203
		$this->cliService->setRunner($this->runner);
204
205
		$this->generatePanels();
206
207
208
		try {
209
			$this->runner->sourceIsCommandLine($this, $output);
210
			$this->runner->start();
211
212
			$this->cliService->runDisplay($output);
213
			$this->generateIndexErrors();
214
			$this->displayError();
215
216
			$this->liveCycle();
217
218
		} catch (Exception $e) {
219
			$this->runner->exception($e->getMessage(), true);
0 ignored issues
show
Deprecated Code introduced by
The method OCA\FullTextSearch\Model\Runner::exception() has been deprecated with message: - verifier l'interet !?

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
220
			throw $e;
221
		}
222
223
		$this->runner->stop();
224
	}
225
226
227
	/**
228
	 * @throws Exception
229
	 * @throws InterruptException
230
	 * @throws TickDoesNotExistException
231
	 */
232
	private function liveCycle() {
233
234
		$platform = $this->platformService->getPlatform();
235
		$platform->setRunner($this->runner);
236
237
		while (true) {
238
239
			$indexes = $this->indexService->getQueuedIndexes();
240
241 View Code Duplication
			foreach ($indexes as $index) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
242
				$this->runner->updateAction('indexing');
243
244
				try {
245
					$provider = $this->providerService->getProvider($index->getProviderId());
246
					$provider->setRunner($this->runner);
247
					$this->indexService->updateDocument($platform, $provider, $index);
248
				} catch (Exception $e) {
249
					$this->runner->exception($e->getMessage(), false);
0 ignored issues
show
Deprecated Code introduced by
The method OCA\FullTextSearch\Model\Runner::exception() has been deprecated with message: - verifier l'interet !?

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
250
					// TODO - upgrade error number - after too many errors, delete index
251
					// TODO - do not count error if elasticsearch is down.
252
				}
253
			}
254
255
			$this->runner->updateAction('waiting', true);
256
257
			usleep(300000);
258
		}
259
260
		$this->runner->stop();
261
262
	}
263
264
265
	/**
266
	 * @param $key
267
	 */
268 View Code Duplication
	public function onKeyPressed($key) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
269
		$key = strtolower($key);
270
		if ($key === 'q') {
271
			try {
272
				$this->runner->stop();
273
			} catch (TickDoesNotExistException $e) {
274
				/** we do nohtin' */
275
			}
276
			exit();
0 ignored issues
show
Coding Style Compatibility introduced by
The method onKeyPressed() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
277
		}
278
279
		$current = $this->cliService->currentPanel('commands');
280
		if ($current === self::PANEL_COMMANDS_ROOT && $key === 'p') {
281
			$this->cliService->switchPanel('commands', self::PANEL_COMMANDS_PAUSED);
282
			$this->runner->pause(true);
283
		}
284
		if ($current === self::PANEL_COMMANDS_PAUSED && $key === 'u') {
285
			$this->cliService->switchPanel('commands', self::PANEL_COMMANDS_ROOT);
286
			$this->runner->pause(false);
287
		}
288
289
		if ($key === 'f') {
290
			$this->displayError(-99);
291
		}
292
		if ($key === 'h') {
293
			$this->displayError(-1);
294
		}
295
		if ($key === 'j') {
296
			$this->displayError(1);
297
		}
298
		if ($key === 'l') {
299
			$this->displayError(99);
300
		}
301
		if ($key === 'd') {
302
			$this->deleteError();
303
		}
304
	}
305
306
307
	/**
308
	 * @param array $error
309
	 */
310
	public function onNewIndexError($error) {
311
		$this->errors[] = $error;
312
		$this->displayError();
313
	}
314
315
316
	/**
317
	 * @param string $action
318
	 */
319 View Code Duplication
	public function onNewAction($action) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
320
321
		if ($action === 'indexChunk' || $action === 'indexChunkEnd') {
322
			$this->runner->setInfoArray(
323
				[
324
					'documentId' => '',
325
					'title'      => '',
326
					'content'    => ''
327
				]
328
			);
329
		}
330
	}
331
332
333
	/**
334
	 *
335
	 */
336 View Code Duplication
	private function generatePanels() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
337
338
		$this->cliService->createPanel(
339
			self::PANEL_RUN,
340
			[
341
				self::PANEL_RUN_LINE_MEMORY
342
			]
343
		);
344
		$this->cliService->createPanel(
345
			self::PANEL_INDEX, [
346
								 self::PANEL_INDEX_LINE_HEADER,
347
								 self::PANEL_INDEX_LINE_ACCOUNT,
348
								 self::PANEL_INDEX_LINE_ACTION,
349
								 self::PANEL_INDEX_LINE_DOCUMENT,
350
								 self::PANEL_INDEX_LINE_INFO,
351
								 self::PANEL_INDEX_LINE_TITLE,
352
								 self::PANEL_INDEX_LINE_CONTENT,
353
								 self::PANEL_INDEX_LINE_RESULT,
354
								 self::PANEL_INDEX_LINE_FOOTER,
355
							 ]
356
		);
357
358
		$this->cliService->createPanel(
359
			self::PANEL_STATUS, [
360
								  self::PANEL_STATUS_LINE_HEADER,
361
								  self::PANEL_STATUS_LINE_DOCUMENTS,
362
								  self::PANEL_STATUS_LINE_ERRORS,
363
								  self::PANEL_STATUS_LINE_ERROR_EXCEPTION,
364
								  self::PANEL_STATUS_LINE_ERROR_MESSAGE1,
365
								  self::PANEL_STATUS_LINE_ERROR_MESSAGE2,
366
								  self::PANEL_STATUS_LINE_ERROR_MESSAGE3,
367
								  self::PANEL_STATUS_LINE_ERROR_INDEX,
368
								  self::PANEL_STATUS_LINE_FOOTER,
369
							  ]
370
		);
371
372
		$this->cliService->createPanel(
373
			self::PANEL_COMMANDS_ROOT, [
374
										 self::PANEL_COMMANDS_ROOT_LINE
375
									 ]
376
		);
377
378
		$this->cliService->createPanel(
379
			self::PANEL_COMMANDS_PAUSED, [
380
										   self::PANEL_COMMANDS_PAUSED_LINE
381
									   ]
382
		);
383
384
		$this->cliService->createPanel(
385
			self::PANEL_COMMANDS_ERRORS, [
386
										   self::PANEL_COMMANDS_ERRORS_LINE
387
									   ]
388
		);
389
390
		$this->cliService->initDisplay();
391
		$this->cliService->displayPanel('run', self::PANEL_RUN);
392
		$this->cliService->displayPanel('topPanel', self::PANEL_INDEX);
393
		$this->cliService->displayPanel('bottomPanel', self::PANEL_STATUS);
394
395
		$this->cliService->displayPanel('errors', self::PANEL_COMMANDS_ERRORS);
396
397
		if ($this->runner->isPaused()) {
398
			$this->cliService->displayPanel('commands', self::PANEL_COMMANDS_PAUSED);
399
		} else {
400
			$this->cliService->displayPanel('commands', self::PANEL_COMMANDS_ROOT);
401
		}
402
403
		$this->runner->setInfoArray(
404
			[
405
				'userId'         => '',
406
				'providerName'   => '',
407
				'_memory'        => '',
408
				'documentId'     => '',
409
				'action'         => '',
410
				'info'           => '',
411
				'title'          => '',
412
				'_paused'        => '',
413
				'content'        => '',
414
				'resultColored'  => '',
415
				'documentLeft'   => '',
416
				'documentTotal'  => '',
417
				'progressStatus' => '',
418
				'errorCurrent'   => '0',
419
				'errorTotal'     => '0',
420
				'errorMessageA'  => '',
421
				'errorMessageB'  => '',
422
				'errorMessageC'  => '',
423
				'errorException' => '',
424
				'errorIndex'     => ''
425
			]
426
		);
427
	}
428
429
430
	/**
431
	 *
432
	 */
433 View Code Duplication
	private function generateIndexErrors() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
434
		$indexes = $this->indexService->getErrorIndexes();
435
436
		foreach ($indexes as $index) {
437
			foreach ($index->getErrors() as $error) {
438
				$this->errors[] = [
439
					'index'     => $index,
440
					'message'   => $error['message'],
441
					'exception' => $error['exception'],
442
					'severity'  => $error['sev']
443
				];
444
			}
445
446
		}
447
448
449
	}
450
451
452
	/**
453
	 * @param int $pos
454
	 */
455 View Code Duplication
	private function displayError($pos = 0) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
456
		$total = sizeof($this->errors);
457
458
		if ($total === 0) {
459
			$this->runner->setInfoArray(
460
				[
461
					'errorCurrent' => 0,
462
					'errorTotal'   => 0,
463
				]
464
			);
465
466
			return;
467
		}
468
469
		$current = key($this->errors) + 1;
470
		$error = $this->getNavigationError($pos, ($current === 1), ($current === $total));
471
		$current = key($this->errors) + 1;
472
473
		if ($error === false) {
474
			return;
475
		}
476
477
		/** @var ModelIndex $index */
478
		$index = $error['index'];
479
		$errorIndex = '';
480
		if ($index !== null) {
481
			$errorIndex = $index->getProviderId() . ':' . $index->getDocumentId();
482
		}
483
484
		$width = $this->terminal->getWidth() - 13;
485
		$message = MiscService::get('message', $error, '');
486
		$err1 = substr($message, 0, $width);
487
		$err2 = substr($message, $width, $width + 10);
488
		$err3 = substr($message, $width + $width + 10, $width + 10);
489
490
		$this->runner->setInfoArray(
491
			[
492
				'errorCurrent'   => $current,
493
				'errorTotal'     => $total,
494
				'errorMessageA'  => trim($err1),
495
				'errorMessageB'  => trim($err2),
496
				'errorMessageC'  => trim($err3),
497
				'errorException' => MiscService::get('exception', $error, ''),
498
				'errorIndex'     => $errorIndex
499
			]
500
		);
501
	}
502
503
504
	/**
505
	 * @param int $pos
506
	 * @param bool $isFirst
507
	 * @param bool $isLast
508
	 *
509
	 * @return bool|array
510
	 */
511 View Code Duplication
	private function getNavigationError($pos, $isFirst, $isLast) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
512
513
		if ($pos === 0) {
514
			if ($this->navigateLastError === true) {
515
				return end($this->errors);
516
			} else {
517
				return current($this->errors);
518
			}
519
		}
520
521
		$this->navigateLastError = false;
522
		if ($pos === -99) {
523
			return reset($this->errors);
524
		}
525
526
		if ($pos === -1 && !$isFirst) {
527
			return prev($this->errors);
528
		}
529
530
		if ($pos === 1 && !$isLast) {
531
			return next($this->errors);
532
		}
533
534
		if ($pos === 99) {
535
			$this->navigateLastError = true;
536
537
			return end($this->errors);
538
		}
539
540
		return false;
541
	}
542
543
544
	/**
545
	 *
546
	 */
547 View Code Duplication
	private function deleteError() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
548
		$current = current($this->errors);
549
		if ($current === false) {
550
			return;
551
		}
552
553
		$this->runner->setInfoArray(
554
			[
555
				'errorMessageA'  => '',
556
				'errorMessageB'  => '',
557
				'errorMessageC'  => '',
558
				'errorException' => '',
559
				'errorIndex'     => ''
560
			]
561
		);
562
563
		$pos = key($this->errors);
564
565
		/** @var ModelIndex $index */
566
		$index = $current['index'];
567
		$this->indexService->resetErrorFromIndex($index);
568
569
		$errors = [];
570
		foreach ($this->errors as $error) {
571
			/** @var ModelIndex $errorIndex */
572
			$errorIndex = $error['index'];
573
			if ($index->getProviderId() === $errorIndex->getProviderId()
574
				&& $index->getDocumentId() === $errorIndex->getDocumentId()) {
575
				continue;
576
			}
577
578
			$errors[] = $error;
579
		}
580
581
		$this->errors = $errors;
582
		while (key($this->errors) < $pos) {
583
			if (next($this->errors) === false) {
584
				end($this->errors);
585
				break;
586
			}
587
		}
588
589
		$this->displayError();
590
	}
591
}
592
593
594
595