Files
VITEC-website/packages/vitec/Classes/Command/SolrIndexCommand.php

146 lines
6.7 KiB
PHP

<?php
declare(strict_types=1);
namespace Evomedien\Vitec\Command;
use ApacheSolrForTypo3\Solr\ConnectionManager;
use ApacheSolrForTypo3\Solr\Domain\Index\IndexService;
use ApacheSolrForTypo3\Solr\Domain\Site\SiteRepository;
use ApacheSolrForTypo3\Solr\IndexQueue\IndexingService;
use ApacheSolrForTypo3\Solr\IndexQueue\Queue;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Throwable;
use TYPO3\CMS\Core\Core\Bootstrap;
use TYPO3\CMS\Core\Utility\GeneralUtility;
/**
* Works the Solr index queue from the CLI - EXT:solr 14 ships no console
* commands, its indexing runs via backend module clicks (1 item each!) or a
* scheduler task. This command fills that gap for cron usage and prints the
* resolved connection state first, because a missing connection makes the
* indexer skip items silently (no error, no queue entry).
*/
#[AsCommand(
name: 'vitec:solr-index',
description: 'Work the Solr index queue and show connection diagnostics',
)]
class SolrIndexCommand extends Command
{
protected function configure(): void
{
$this->addOption('limit', 'l', InputOption::VALUE_REQUIRED, 'Max queue items to index in this run', '20');
$this->addOption('root', 'r', InputOption::VALUE_REQUIRED, 'Root page uid of the site', '1');
$this->addOption('debug', 'd', InputOption::VALUE_NONE, 'Single-step the first queue item verbosely');
$this->addOption('initialize', 'i', InputOption::VALUE_REQUIRED, 'Initialize the index queue for these configurations (comma list or *) before indexing');
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
Bootstrap::initializeBackendAuthentication();
$rootPageId = (int)$input->getOption('root');
$limit = (int)$input->getOption('limit');
$siteRepository = GeneralUtility::makeInstance(SiteRepository::class);
$site = $siteRepository->getSiteByRootPageId($rootPageId);
$configs = $site->getAllSolrConnectionConfigurations();
$output->writeln('Connection configurations: ' . count($configs));
foreach ($configs as $languageId => $config) {
$read = $config['read'];
$output->writeln(sprintf(
' lang %d: %s://%s:%d%s core=%s auth=%s',
$languageId,
$read['scheme'],
$read['host'],
$read['port'],
$read['path'],
$read['core'],
$read['username'] !== '' ? 'yes' : 'no',
));
}
if ($configs === []) {
$output->writeln('<error>No connection configuration resolved - check site config.</error>');
return Command::FAILURE;
}
$initialize = (string)($input->getOption('initialize') ?? '');
if ($initialize !== '') {
$names = $initialize === '*' ? ['*'] : array_map('trim', explode(',', $initialize));
$initService = GeneralUtility::makeInstance(\ApacheSolrForTypo3\Solr\Domain\Index\Queue\QueueInitializationService::class);
$result = $initService->initializeBySiteAndIndexConfigurations($site, $names);
foreach ($result as $name => $ok) {
$output->writeln(' initialized ' . $name . ': ' . var_export($ok, true));
}
}
if ($input->getOption('debug')) {
$queueConfig = $site->getSolrConfiguration()->getObjectByPathOrDefault('plugin.tx_solr.index.queue.');
$output->writeln('index.queue keys: ' . implode(', ', array_keys($queueConfig)));
$output->writeln('products.table: ' . var_export($queueConfig['products.']['table'] ?? null, true));
$queue = GeneralUtility::makeInstance(Queue::class);
$items = $queue->getItemsToIndex($site, 5);
$output->writeln('getItemsToIndex(5): ' . count($items) . ' items');
if ($items !== []) {
$first = $items[0];
$output->writeln(' first: type=' . $first->getType() . ' uid=' . $first->getRecordUid());
$svc = GeneralUtility::getContainer()->get(IndexingService::class);
$ref = new \ReflectionObject($svc);
$call = static function (string $method, array $args) use ($svc, $ref) {
$m = $ref->getMethod($method);
return $m->invokeArgs($svc, $args);
};
$conns = $call('getPageSolrConnections', [$first]);
$output->writeln(' getPageSolrConnections: ' . count($conns) . ' connections (langs: ' . implode(',', array_keys($conns)) . ')');
if ($conns === []) {
return Command::SUCCESS;
}
$groups = $call('findUserGroupsForPage', [$first, 0]);
$output->writeln(' findUserGroupsForPage(lang 0): ' . json_encode($groups));
$accessRootline = $call('buildAccessRootline', [$first, 0, $groups[0] ?? 0]);
$params = $call('buildPageParameters', [$first]);
$instructions = new \ApacheSolrForTypo3\Solr\IndexQueue\IndexingInstructions(
items: [$first],
action: \ApacheSolrForTypo3\Solr\IndexQueue\IndexingInstructions::ACTION_INDEX_PAGE,
language: 0,
userGroup: (int)($groups[0] ?? 0),
accessRootline: $accessRootline,
parameters: $params,
);
$response = $call('executeSubRequest', [$first, 0, $instructions]);
if ($response === null) {
$output->writeln(' executeSubRequest => NULL (siehe Log)');
} else {
$output->writeln(' executeSubRequest => HTTP ' . $response->getStatusCode()
. ' content-type=' . $response->getHeaderLine('Content-Type'));
$body = (string)$response->getBody();
$output->writeln(' body (600 Zeichen): ' . substr($body, 0, 600));
}
}
return Command::SUCCESS;
}
$indexService = GeneralUtility::makeInstance(IndexService::class, $site);
try {
$success = $indexService->indexItems($limit);
} catch (Throwable $e) {
$output->writeln('<error>indexItems threw: ' . $e->getMessage() . '</error>');
$output->writeln($e->getTraceAsString());
return Command::FAILURE;
}
$output->writeln('indexItems(' . $limit . ') returned: ' . ($success ? 'success' : 'with errors'));
return Command::SUCCESS;
}
}