diff --git a/src/Command/MeilisearchIndexCommand.php b/src/Command/MeilisearchIndexCommand.php index 7abc917..f12185a 100644 --- a/src/Command/MeilisearchIndexCommand.php +++ b/src/Command/MeilisearchIndexCommand.php @@ -9,7 +9,7 @@ use Symfony\Component\Console\Output\OutputInterface; #[AsCommand( name: 'meilisearch:index', - description: 'Rebuild Meilisearch index' + description: 'Rebuild Meilisearch index from Contao search tables' )] class MeilisearchIndexCommand extends Command { diff --git a/src/Service/MeilisearchIndexService.php b/src/Service/MeilisearchIndexService.php index 28331fa..471ed12 100644 --- a/src/Service/MeilisearchIndexService.php +++ b/src/Service/MeilisearchIndexService.php @@ -1,25 +1,139 @@ indexName = Config::get('meilisearch_index'); + + $this->client = new Client($host, $apiKey); + } + + /** + * Entry point for command & cron + */ public function run(): void { - // hier später: - // - Seiten / Events / News laden - // - normalisieren - // - an Meilisearch senden + $index = $this->client->index($this->indexName); - $this->logger->info('Meilisearch indexing started'); + // 1. kompletten Index löschen + $index->deleteAllDocuments(); - // TODO: Indexierung + // 2. tl_search indexieren + $this->indexTlSearch($index); - $this->logger->info('Meilisearch indexing finished'); + // 3. tl_search_pdf indexieren + $this->indexTlSearchPdf($index); } -} + + /** + * Indexiert Seiten, Events und News aus tl_search + */ + private function indexTlSearch($index): void + { + $rows = $this->connection->fetchAllAssociative( + 'SELECT * FROM tl_search' + ); + + if (!$rows) { + return; + } + + $documents = []; + + foreach ($rows as $row) { + $type = $this->detectTypeFromMeta($row['meta'] ?? null); + + $documents[] = [ + 'id' => $type . '_' . $row['id'], + 'type' => $type, + 'title' => $row['title'], + 'text' => $row['text'], + 'url' => $row['url'], + 'protected' => (bool) $row['protected'], + 'pid' => $row['pid'], + 'checksum' => $row['checksum'], + ]; + } + + $index->addDocuments($documents); + } + + /** + * Indexiert PDFs aus tl_search_pdf + */ + private function indexTlSearchPdf($index): void + { + $rows = $this->connection->fetchAllAssociative( + 'SELECT * FROM tl_search_pdf' + ); + + if (!$rows) { + return; + } + + $documents = []; + + foreach ($rows as $row) { + $fileType = $row['type'] ?: 'pdf'; + + $documents[] = [ + 'id' => $fileType . '_' . $row['id'], + 'type' => $fileType, + 'title' => $row['title'], + 'text' => $row['content'], + 'url' => $row['url'], + 'pid' => $row['pid'], + 'checksum' => $row['checksum'], + 'filesrc' => $row['filesrc'], + ]; + } + + $index->addDocuments($documents); + } + + /** + * Robuste Typ-Erkennung ausschließlich über tl_search.meta + * + * @return page|event|news + */ + private function detectTypeFromMeta(?string $meta): string + { + if (!$meta) { + return 'page'; + } + + $data = json_decode($meta, true); + if (!is_array($data)) { + return 'page'; + } + + foreach ($data as $entry) { + if (!isset($entry['@type'])) { + continue; + } + + switch ($entry['@type']) { + case 'https://schema.org/Event': + return 'event'; + + case 'https://schema.org/NewsArticle': + return 'news'; + } + } + + return 'page'; + } +} \ No newline at end of file