Add Solr search: EXT:solr 14 integration and JSON search endpoint
Apache Solr 10 runs on a dedicated VPS behind a Caddy HTTPS proxy (vitecsolr.evomedien.de) because the managed webserver only allows outgoing standard ports. Credentials stay out of git: the site config carries %env()% placeholders resolved via putenv() in the git-ignored config/system/additional.php. - composer: apache-solr-for-typo3/solr 14.0.0-RC1 (the only line compatible with TYPO3 14; final 14.0.0 will arrive via composer update) - config.yaml: read connection https/443, core_en per language, env placeholder credentials; .gitignore covers additional.php - setup.typoscript: config.index_enable = 1 (page indexing silently refuses without it), solr_pi_results JSON renderer registration, results highlighting, and content field extraction from tt_content rows - the headless JSON output has no TYPO3SEARCH markers, so the default page content extraction indexed an empty content field - SearchJsonRenderer (renderer #27): JSON output for the search plugin on /search. GET q/page in; { query, page, resultsPerPage, numFound, totalPages, results[], suggestions } out. Disables the page cache per request: config.no_cache is gone in TYPO3 v14, and q/page are excluded from cHash, so cached variants would collide - ext_localconf.php: q and page added to cacheHash excludedParameters - SolrIndexCommand (vitec:solr-index): works the index queue from the CLI with connection diagnostics and a --debug single-step mode - EXT:solr 14 ships no console commands and the backend button indexes one item per click
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -10,6 +10,7 @@
|
|||||||
.env.*
|
.env.*
|
||||||
!.env.example
|
!.env.example
|
||||||
/config/system/settings.php
|
/config/system/settings.php
|
||||||
|
/config/system/additional.php
|
||||||
auth.json
|
auth.json
|
||||||
|
|
||||||
# --------------------------------------------------
|
# --------------------------------------------------
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
"sort-packages": true
|
"sort-packages": true
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
"apache-solr-for-typo3/solr": "^14.0@RC",
|
||||||
"b13/container": "^3.1",
|
"b13/container": "^3.1",
|
||||||
"b13/typo3-updater": "^1.1",
|
"b13/typo3-updater": "^1.1",
|
||||||
"evomedien/vitec": "^1.0.1",
|
"evomedien/vitec": "^1.0.1",
|
||||||
|
|||||||
332
composer.lock
generated
332
composer.lock
generated
@@ -4,8 +4,123 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "727d61bcbce8571b4b05c61cf61813aa",
|
"content-hash": "d902283b2e3364081e0daec494c39cef",
|
||||||
"packages": [
|
"packages": [
|
||||||
|
{
|
||||||
|
"name": "apache-solr-for-typo3/solr",
|
||||||
|
"version": "14.0.0-RC1",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/TYPO3-Solr/ext-solr.git",
|
||||||
|
"reference": "96834e83592d59c350005216821ee502cfee8ece"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/TYPO3-Solr/ext-solr/zipball/96834e83592d59c350005216821ee502cfee8ece",
|
||||||
|
"reference": "96834e83592d59c350005216821ee502cfee8ece",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-dom": "*",
|
||||||
|
"ext-json": "*",
|
||||||
|
"ext-libxml": "*",
|
||||||
|
"ext-pdo": "*",
|
||||||
|
"ext-simplexml": "*",
|
||||||
|
"php": "^8.2",
|
||||||
|
"solarium/solarium": "7.0.0",
|
||||||
|
"typo3/cms-backend": "*",
|
||||||
|
"typo3/cms-core": "^v14.3.0",
|
||||||
|
"typo3/cms-extbase": "*",
|
||||||
|
"typo3/cms-fluid": "*",
|
||||||
|
"typo3/cms-frontend": "*",
|
||||||
|
"typo3/cms-install": "*",
|
||||||
|
"typo3/cms-reports": "*",
|
||||||
|
"typo3/cms-scheduler": "*",
|
||||||
|
"typo3/cms-tstemplate": "*"
|
||||||
|
},
|
||||||
|
"replace": {
|
||||||
|
"apache-solr-for-typo3/solrfluid": "*",
|
||||||
|
"apache-solr-for-typo3/solrfluidgrouping": "*",
|
||||||
|
"typo3-ter/solr": "self.version",
|
||||||
|
"typo3-ter/solrfluid": "*",
|
||||||
|
"typo3-ter/solrfluidgrouping": "*"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"brianium/paratest": "^7.8.5",
|
||||||
|
"dg/bypass-finals": "^1.9",
|
||||||
|
"phpstan/phpstan": "^2.1.34",
|
||||||
|
"phpstan/phpstan-phpunit": "^2.0.18",
|
||||||
|
"phpunit/phpunit": "^11.5.55",
|
||||||
|
"typo3/cms-fluid-styled-content": "*",
|
||||||
|
"typo3/coding-standards": "v0.8.0",
|
||||||
|
"typo3/testing-framework": "^9.5.0"
|
||||||
|
},
|
||||||
|
"type": "typo3-cms-extension",
|
||||||
|
"extra": {
|
||||||
|
"typo3/cms": {
|
||||||
|
"web-dir": ".Build/Web",
|
||||||
|
"extension-key": "solr"
|
||||||
|
},
|
||||||
|
"TYPO3-Solr": {
|
||||||
|
"ext-solrfal": [],
|
||||||
|
"stack-for-ci": {
|
||||||
|
"sclable/xml-lint": "*"
|
||||||
|
},
|
||||||
|
"version-matrix": {
|
||||||
|
"ext-tika": "^14.0",
|
||||||
|
"configset": "ext_solr_14_0_0",
|
||||||
|
"Apache-Solr": [
|
||||||
|
"10.0.0"
|
||||||
|
],
|
||||||
|
"ext-solrfal": "^14.0",
|
||||||
|
"ext-solrconsole": "^14.0",
|
||||||
|
"ext-solrdebugtools": "^14.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-main": "14.0.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"ApacheSolrForTypo3\\Solr\\": "Classes/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"GPL-3.0-or-later"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "dkd Internet Service GmbH",
|
||||||
|
"email": "info@dkd.de",
|
||||||
|
"homepage": "https://www.dkd.de"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Apache Solr for TYPO3 - Apache Solr for TYPO3 is the enterprise search server you were looking for with special features such as Faceted Search or Synonym Support and incredibly fast response times of results within milliseconds.",
|
||||||
|
"homepage": "https://www.typo3-solr.com",
|
||||||
|
"keywords": [
|
||||||
|
"TYPO3 CMS",
|
||||||
|
"search",
|
||||||
|
"solr",
|
||||||
|
"typo3"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"docs": "https://docs.typo3.org/p/apache-solr-for-typo3/solr/main/en-us/",
|
||||||
|
"email": "info@dkd.de",
|
||||||
|
"forum": "https://talk.typo3.org",
|
||||||
|
"issues": "https://github.com/TYPO3-Solr/ext-solr/issues",
|
||||||
|
"slack": "https://typo3.slack.com/archives/C02FF05Q4",
|
||||||
|
"source": "https://github.com/TYPO3-Solr/ext-solr"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://www.typo3-solr.com/",
|
||||||
|
"type": "custom"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2026-07-17T15:16:50+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "b13/container",
|
"name": "b13/container",
|
||||||
"version": "3.2.3",
|
"version": "3.2.3",
|
||||||
@@ -2015,6 +2130,68 @@
|
|||||||
],
|
],
|
||||||
"time": "2026-07-16T22:23:49+00:00"
|
"time": "2026-07-16T22:23:49+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "halaxa/json-machine",
|
||||||
|
"version": "1.2.6",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/halaxa/json-machine.git",
|
||||||
|
"reference": "8bf0b0ff6ff60ab480778eaa5ad7d505b442c2d4"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/halaxa/json-machine/zipball/8bf0b0ff6ff60ab480778eaa5ad7d505b442c2d4",
|
||||||
|
"reference": "8bf0b0ff6ff60ab480778eaa5ad7d505b442c2d4",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "7.2 - 8.5"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"ext-json": "*",
|
||||||
|
"friendsofphp/php-cs-fixer": "^3.0",
|
||||||
|
"phpstan/phpstan": "^1.10",
|
||||||
|
"phpunit/phpunit": "^8.0"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"ext-json": "To run JSON Machine out of the box without custom decoders.",
|
||||||
|
"guzzlehttp/guzzle": "To run example with GuzzleHttp"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"files": [
|
||||||
|
"src/functions.php"
|
||||||
|
],
|
||||||
|
"psr-4": {
|
||||||
|
"JsonMachine\\": "src/"
|
||||||
|
},
|
||||||
|
"exclude-from-classmap": [
|
||||||
|
"src/autoloader.php"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"Apache-2.0"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Filip Halaxa",
|
||||||
|
"email": "filip@halaxa.cz"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Efficient, easy-to-use and fast JSON pull parser",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/halaxa/json-machine/issues",
|
||||||
|
"source": "https://github.com/halaxa/json-machine/tree/1.2.6"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://ko-fi.com/G2G57KTE4",
|
||||||
|
"type": "other"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2025-12-05T14:53:09+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "justinrainbow/json-schema",
|
"name": "justinrainbow/json-schema",
|
||||||
"version": "6.10.0",
|
"version": "6.10.0",
|
||||||
@@ -4052,6 +4229,82 @@
|
|||||||
},
|
},
|
||||||
"time": "2023-09-03T09:24:00+00:00"
|
"time": "2023-09-03T09:24:00+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "solarium/solarium",
|
||||||
|
"version": "7.0.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/solariumphp/solarium.git",
|
||||||
|
"reference": "44739c15341c308ea5ba79942fa4c9f4198679c4"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/solariumphp/solarium/zipball/44739c15341c308ea5ba79942fa4c9f4198679c4",
|
||||||
|
"reference": "44739c15341c308ea5ba79942fa4c9f4198679c4",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"composer-runtime-api": ">=2.0",
|
||||||
|
"ext-date": "*",
|
||||||
|
"ext-json": "*",
|
||||||
|
"ext-pcre": "*",
|
||||||
|
"halaxa/json-machine": "^1.1",
|
||||||
|
"php": "^8.1",
|
||||||
|
"psr/event-dispatcher": "^1.0",
|
||||||
|
"psr/http-client": "^1.0",
|
||||||
|
"psr/http-factory": "^1.0",
|
||||||
|
"symfony/event-dispatcher-contracts": "^2.0 || ^3.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"2tvenom/cborencode": "^1.0",
|
||||||
|
"escapestudios/symfony2-coding-standard": "^3.11",
|
||||||
|
"ext-curl": "*",
|
||||||
|
"ext-iconv": "*",
|
||||||
|
"nyholm/psr7": "^1.8",
|
||||||
|
"php-http/guzzle7-adapter": "^1.0",
|
||||||
|
"phpstan/extension-installer": "^1.4",
|
||||||
|
"phpstan/phpstan": "^2.1.41",
|
||||||
|
"phpstan/phpstan-deprecation-rules": "^2.0",
|
||||||
|
"phpstan/phpstan-phpunit": "^2.0",
|
||||||
|
"phpunit/phpunit": "^10.5",
|
||||||
|
"rawr/phpunit-data-provider": "^3.3",
|
||||||
|
"roave/security-advisories": "dev-master",
|
||||||
|
"spomky-labs/cbor-php": "^3.1",
|
||||||
|
"symfony/event-dispatcher": "^5.0 || ^6.0 || ^7.0 || ^8.0"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"ext-curl": "Needed to use the cURL adapter",
|
||||||
|
"spomky-labs/cbor-php": "Needed to use CBOR formatted requests with Solr 9.3+"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Solarium\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"BSD-3-Clause"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "See GitHub contributors",
|
||||||
|
"homepage": "https://github.com/solariumphp/solarium/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "PHP Solr client",
|
||||||
|
"homepage": "http://www.solarium-project.org",
|
||||||
|
"keywords": [
|
||||||
|
"php",
|
||||||
|
"search",
|
||||||
|
"solr"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/solariumphp/solarium/issues",
|
||||||
|
"source": "https://github.com/solariumphp/solarium/tree/7.0.0"
|
||||||
|
},
|
||||||
|
"time": "2026-04-27T07:40:48+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/cache",
|
"name": "symfony/cache",
|
||||||
"version": "v8.0.15",
|
"version": "v8.0.15",
|
||||||
@@ -9238,6 +9491,76 @@
|
|||||||
],
|
],
|
||||||
"time": "2026-08-11T07:21:33+00:00"
|
"time": "2026-08-11T07:21:33+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "typo3/cms-reports",
|
||||||
|
"version": "v14.3.6",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/TYPO3-CMS/reports.git",
|
||||||
|
"reference": "4e28680d94dd21f149a045a847ccb4f42b452843"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/TYPO3-CMS/reports/zipball/4e28680d94dd21f149a045a847ccb4f42b452843",
|
||||||
|
"reference": "4e28680d94dd21f149a045a847ccb4f42b452843",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"typo3/cms-core": "14.3.6"
|
||||||
|
},
|
||||||
|
"conflict": {
|
||||||
|
"typo3/cms": "*"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"typo3/cms-scheduler": "Determine system's status and send it via email"
|
||||||
|
},
|
||||||
|
"type": "typo3-cms-framework",
|
||||||
|
"extra": {
|
||||||
|
"typo3/cms": {
|
||||||
|
"Package": {
|
||||||
|
"partOfFactoryDefault": true
|
||||||
|
},
|
||||||
|
"extension-key": "reports"
|
||||||
|
},
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-main": "14.3.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"TYPO3\\CMS\\Reports\\": "Classes/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"GPL-2.0-or-later"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "TYPO3 Core Team",
|
||||||
|
"email": "typo3cms@typo3.org",
|
||||||
|
"role": "Developer"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "TYPO3 CMS Reports - Show status reports and installed services in the (System>Reports) backend module.",
|
||||||
|
"homepage": "https://typo3.community/",
|
||||||
|
"support": {
|
||||||
|
"chat": "https://typo3.community/meet/slack/",
|
||||||
|
"docs": "https://docs.typo3.org/",
|
||||||
|
"forum": "https://talk.typo3.org/",
|
||||||
|
"issues": "https://forge.typo3.org/issues/",
|
||||||
|
"rss": "https://news.typo3.com/rss/",
|
||||||
|
"security": "https://typo3.org/security/",
|
||||||
|
"source": "https://github.com/TYPO3/typo3/"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://typo3.org/membership",
|
||||||
|
"type": "membership"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2026-08-11T07:21:33+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "typo3/cms-rte-ckeditor",
|
"name": "typo3/cms-rte-ckeditor",
|
||||||
"version": "v14.3.6",
|
"version": "v14.3.6",
|
||||||
@@ -9895,14 +10218,15 @@
|
|||||||
"aliases": [],
|
"aliases": [],
|
||||||
"minimum-stability": "stable",
|
"minimum-stability": "stable",
|
||||||
"stability-flags": {
|
"stability-flags": {
|
||||||
|
"apache-solr-for-typo3/solr": 5,
|
||||||
"friendsoftypo3/headless": 5
|
"friendsoftypo3/headless": 5
|
||||||
},
|
},
|
||||||
"prefer-stable": false,
|
"prefer-stable": false,
|
||||||
"prefer-lowest": false,
|
"prefer-lowest": false,
|
||||||
"platform": [],
|
"platform": {},
|
||||||
"platform-dev": [],
|
"platform-dev": {},
|
||||||
"platform-overrides": {
|
"platform-overrides": {
|
||||||
"php": "8.4.0"
|
"php": "8.4.0"
|
||||||
},
|
},
|
||||||
"plugin-api-version": "2.3.0"
|
"plugin-api-version": "2.9.0"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
base: /
|
base: 'https://dev.vitec.com/'
|
||||||
dependencies:
|
dependencies:
|
||||||
- typo3/fluid-styled-content
|
- typo3/fluid-styled-content
|
||||||
- typo3/fluid-styled-content-css
|
- typo3/fluid-styled-content-css
|
||||||
@@ -20,6 +20,10 @@ dependencies:
|
|||||||
- georgringer/news-sitemap
|
- georgringer/news-sitemap
|
||||||
- georgringer/news-recordlinks
|
- georgringer/news-recordlinks
|
||||||
- vitec/columns
|
- vitec/columns
|
||||||
|
- apache-solr-for-typo3/solr
|
||||||
|
- apache-solr-for-typo3/solr-open-search
|
||||||
|
- apache-solr-for-typo3/solr-stylesheets
|
||||||
|
- apache-solr-for-typo3/solr-bootstrap-css
|
||||||
frontendBase: ''
|
frontendBase: ''
|
||||||
headless: 1
|
headless: 1
|
||||||
languages:
|
languages:
|
||||||
@@ -31,6 +35,7 @@ languages:
|
|||||||
locale: en_US.UTF-8
|
locale: en_US.UTF-8
|
||||||
navigationTitle: English
|
navigationTitle: English
|
||||||
flag: us
|
flag: us
|
||||||
|
solr_core_read: core_en
|
||||||
rootPageId: 1
|
rootPageId: 1
|
||||||
routeEnhancers:
|
routeEnhancers:
|
||||||
ProductPlugin:
|
ProductPlugin:
|
||||||
@@ -61,7 +66,8 @@ routeEnhancers:
|
|||||||
extension: News
|
extension: News
|
||||||
plugin: Pi1
|
plugin: Pi1
|
||||||
routes:
|
routes:
|
||||||
- routePath: '/{news-title}'
|
-
|
||||||
|
routePath: '/{news-title}'
|
||||||
_controller: 'News::detail'
|
_controller: 'News::detail'
|
||||||
_arguments:
|
_arguments:
|
||||||
news-title: news
|
news-title: news
|
||||||
@@ -91,4 +97,16 @@ routeEnhancers:
|
|||||||
type: PersistedAliasMapper
|
type: PersistedAliasMapper
|
||||||
tableName: tx_vitec_domain_model_usecase
|
tableName: tx_vitec_domain_model_usecase
|
||||||
routeFieldName: slug
|
routeFieldName: slug
|
||||||
|
solr_enabled_read: true
|
||||||
|
solr_host_read: vitecsolr.evomedien.de
|
||||||
|
solr_host_write: localhost
|
||||||
|
solr_path_read: /
|
||||||
|
solr_path_write: /
|
||||||
|
solr_port_read: '443'
|
||||||
|
solr_port_write: '8983'
|
||||||
|
solr_scheme_read: https
|
||||||
|
solr_scheme_write: ''
|
||||||
|
solr_use_write_connection: false
|
||||||
|
solr_username_read: '%env(SOLR_USERNAME)%'
|
||||||
|
solr_password_read: '%env(SOLR_PASSWORD)%'
|
||||||
websiteTitle: ''
|
websiteTitle: ''
|
||||||
|
|||||||
130
packages/vitec/Classes/Command/SolrIndexCommand.php
Normal file
130
packages/vitec/Classes/Command/SolrIndexCommand.php
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
<?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');
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($input->getOption('debug')) {
|
||||||
|
$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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,6 +20,7 @@ use Evomedien\Vitec\UserFunc\CustomerlogosJsonRenderer;
|
|||||||
use Evomedien\Vitec\UserFunc\FormsJsonRenderer;
|
use Evomedien\Vitec\UserFunc\FormsJsonRenderer;
|
||||||
use Evomedien\Vitec\UserFunc\ModelcardJsonRenderer;
|
use Evomedien\Vitec\UserFunc\ModelcardJsonRenderer;
|
||||||
use Evomedien\Vitec\UserFunc\NewsJsonRenderer;
|
use Evomedien\Vitec\UserFunc\NewsJsonRenderer;
|
||||||
|
use Evomedien\Vitec\UserFunc\SearchJsonRenderer;
|
||||||
use TYPO3\CMS\Core\Database\Connection;
|
use TYPO3\CMS\Core\Database\Connection;
|
||||||
use TYPO3\CMS\Core\Database\ConnectionPool;
|
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||||
@@ -132,6 +133,7 @@ final class ContainerChildrenProcessor implements DataProcessorInterface
|
|||||||
'vitec_contactform' => [FormsJsonRenderer::class, 'form'],
|
'vitec_contactform' => [FormsJsonRenderer::class, 'form'],
|
||||||
'vitec_demoform' => [FormsJsonRenderer::class, 'form'],
|
'vitec_demoform' => [FormsJsonRenderer::class, 'form'],
|
||||||
'vitec_helpdeskform' => [FormsJsonRenderer::class, 'form'],
|
'vitec_helpdeskform' => [FormsJsonRenderer::class, 'form'],
|
||||||
|
'solr_pi_results' => [SearchJsonRenderer::class, 'search'],
|
||||||
'news_pi1' => [NewsJsonRenderer::class, 'news'],
|
'news_pi1' => [NewsJsonRenderer::class, 'news'],
|
||||||
'news_newsliststicky' => [NewsJsonRenderer::class, 'news'],
|
'news_newsliststicky' => [NewsJsonRenderer::class, 'news'],
|
||||||
'news_newsselectedlist' => [NewsJsonRenderer::class, 'news'],
|
'news_newsselectedlist' => [NewsJsonRenderer::class, 'news'],
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ use Evomedien\Vitec\UserFunc\CustomerlogosJsonRenderer;
|
|||||||
use Evomedien\Vitec\UserFunc\FormsJsonRenderer;
|
use Evomedien\Vitec\UserFunc\FormsJsonRenderer;
|
||||||
use Evomedien\Vitec\UserFunc\ModelcardJsonRenderer;
|
use Evomedien\Vitec\UserFunc\ModelcardJsonRenderer;
|
||||||
use Evomedien\Vitec\UserFunc\NewsJsonRenderer;
|
use Evomedien\Vitec\UserFunc\NewsJsonRenderer;
|
||||||
|
use Evomedien\Vitec\UserFunc\SearchJsonRenderer;
|
||||||
use Evomedien\Vitec\UserFunc\ContainerBackgroundRenderer;
|
use Evomedien\Vitec\UserFunc\ContainerBackgroundRenderer;
|
||||||
use TYPO3\CMS\Core\Database\ConnectionPool;
|
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||||
@@ -130,6 +131,7 @@ final class ContentElementResolver
|
|||||||
'vitec_contactform' => [FormsJsonRenderer::class, 'form'],
|
'vitec_contactform' => [FormsJsonRenderer::class, 'form'],
|
||||||
'vitec_demoform' => [FormsJsonRenderer::class, 'form'],
|
'vitec_demoform' => [FormsJsonRenderer::class, 'form'],
|
||||||
'vitec_helpdeskform' => [FormsJsonRenderer::class, 'form'],
|
'vitec_helpdeskform' => [FormsJsonRenderer::class, 'form'],
|
||||||
|
'solr_pi_results' => [SearchJsonRenderer::class, 'search'],
|
||||||
'news_pi1' => [NewsJsonRenderer::class, 'news'],
|
'news_pi1' => [NewsJsonRenderer::class, 'news'],
|
||||||
'news_newsliststicky' => [NewsJsonRenderer::class, 'news'],
|
'news_newsliststicky' => [NewsJsonRenderer::class, 'news'],
|
||||||
'news_newsselectedlist' => [NewsJsonRenderer::class, 'news'],
|
'news_newsselectedlist' => [NewsJsonRenderer::class, 'news'],
|
||||||
|
|||||||
227
packages/vitec/Classes/UserFunc/SearchJsonRenderer.php
Normal file
227
packages/vitec/Classes/UserFunc/SearchJsonRenderer.php
Normal file
@@ -0,0 +1,227 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Evomedien\Vitec\UserFunc;
|
||||||
|
|
||||||
|
use ApacheSolrForTypo3\Solr\ConnectionManager;
|
||||||
|
use ApacheSolrForTypo3\Solr\Domain\Search\ResultSet\SearchResultSetService;
|
||||||
|
use ApacheSolrForTypo3\Solr\Domain\Search\SearchRequestBuilder;
|
||||||
|
use ApacheSolrForTypo3\Solr\Search;
|
||||||
|
use ApacheSolrForTypo3\Solr\System\Configuration\ConfigurationManager;
|
||||||
|
use ApacheSolrForTypo3\Solr\System\Service\ConfigurationService;
|
||||||
|
use Doctrine\DBAL\ParameterType;
|
||||||
|
use TYPO3\CMS\Core\Attribute\AsAllowedCallable;
|
||||||
|
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||||
|
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||||
|
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UserFunc: render EXT:solr search results as JSON (headless).
|
||||||
|
*
|
||||||
|
* Output under content.search:
|
||||||
|
* {
|
||||||
|
* "query": the search terms as used,
|
||||||
|
* "page": 1-based current page,
|
||||||
|
* "resultsPerPage": page size (plugin.tx_solr.search.results.resultsPerPage
|
||||||
|
* or the FlexForm override on the plugin),
|
||||||
|
* "numFound": total hits,
|
||||||
|
* "totalPages": ceil(numFound / resultsPerPage),
|
||||||
|
* "results": [ { "title", "url", "type", "teaser" } ],
|
||||||
|
* "suggestions": spellcheck alternatives ("did you mean"), [] if none
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* Request parameters (GET, on the page carrying the plugin):
|
||||||
|
* q = search terms; without it the empty shape above is returned
|
||||||
|
* (numFound 0) so the frontend always sees the same structure
|
||||||
|
* page = 1-based page number, optional
|
||||||
|
* The EXT:solr namespace (tx_solr[q], tx_solr[page]) is accepted as a
|
||||||
|
* fallback so classic solr URLs keep working.
|
||||||
|
*
|
||||||
|
* The search itself is EXT:solr's own pipeline (SearchRequestBuilder ->
|
||||||
|
* SearchResultSetService), i.e. identical to what the Fluid plugin runs -
|
||||||
|
* only the rendering is JSON instead of HTML. `teaser` carries the
|
||||||
|
* highlighted fragment when highlighting is enabled, otherwise a plain
|
||||||
|
* 250-char excerpt of the indexed content.
|
||||||
|
*
|
||||||
|
* `render()` = top-level plugin / page discovery. `renderForRecord()` = one
|
||||||
|
* specific tt_content row (reused by ContainerChildrenProcessor for nested
|
||||||
|
* plugins). Exception-safe.
|
||||||
|
*/
|
||||||
|
class SearchJsonRenderer
|
||||||
|
{
|
||||||
|
private ?ContentObjectRenderer $cObj = null;
|
||||||
|
|
||||||
|
/** Same duck-typed setter contract as the other renderers (see MarketListJsonRenderer). */
|
||||||
|
public function setContentObjectRenderer(ContentObjectRenderer $cObj): void
|
||||||
|
{
|
||||||
|
$this->cObj = $cObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
private const CTYPE = 'solr_pi_results';
|
||||||
|
private const TEASER_FALLBACK_LENGTH = 250;
|
||||||
|
|
||||||
|
#[AsAllowedCallable]
|
||||||
|
public function render(string $content, array $conf): string
|
||||||
|
{
|
||||||
|
$row = is_array($this->cObj?->data ?? null) ? $this->cObj->data : null;
|
||||||
|
if ($row && (string)($row['CType'] ?? '') === self::CTYPE) {
|
||||||
|
return $this->renderForRecord($row);
|
||||||
|
}
|
||||||
|
|
||||||
|
$pageId = 0;
|
||||||
|
$request = $GLOBALS['TYPO3_REQUEST'] ?? null;
|
||||||
|
if ($request !== null) {
|
||||||
|
$pageInfo = $request->getAttribute('frontend.page.information');
|
||||||
|
if ($pageInfo !== null) {
|
||||||
|
$pageId = (int)$pageInfo->getId();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($pageId <= 0) {
|
||||||
|
$pageId = (int)($GLOBALS['TSFE']->id ?? 0);
|
||||||
|
}
|
||||||
|
if ($pageId <= 0) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$qb = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tt_content');
|
||||||
|
$ces = $qb
|
||||||
|
->select('*')
|
||||||
|
->from('tt_content')
|
||||||
|
->where(
|
||||||
|
$qb->expr()->eq('pid', $qb->createNamedParameter($pageId, ParameterType::INTEGER)),
|
||||||
|
$qb->expr()->eq('CType', $qb->createNamedParameter(self::CTYPE, ParameterType::STRING)),
|
||||||
|
$qb->expr()->eq('deleted', 0),
|
||||||
|
$qb->expr()->eq('hidden', 0)
|
||||||
|
)
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAllAssociative();
|
||||||
|
|
||||||
|
if (empty($ces)) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->renderForRecord($ces[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array<string,mixed> $contentElement
|
||||||
|
*/
|
||||||
|
public function renderForRecord(array $contentElement): string
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$request = $GLOBALS['TYPO3_REQUEST'] ?? null;
|
||||||
|
if ($request === null) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search responses depend on the q/page GET parameters, which are
|
||||||
|
// excluded from cHash - cached variants would collide (config.no_cache
|
||||||
|
// is gone in TYPO3 v14, so the cache is disabled per request here).
|
||||||
|
$request->getAttribute('frontend.cache.instruction')
|
||||||
|
?->disableCache('vitec search: response varies by q/page query parameters');
|
||||||
|
|
||||||
|
$params = $request->getQueryParams();
|
||||||
|
$solrNamespace = (array)($params['tx_solr'] ?? []);
|
||||||
|
$query = trim((string)($params['q'] ?? $solrNamespace['q'] ?? ''));
|
||||||
|
$page = max(1, (int)($params['page'] ?? $solrNamespace['page'] ?? 1));
|
||||||
|
|
||||||
|
if ($query === '') {
|
||||||
|
return (string)json_encode($this->emptyResult());
|
||||||
|
}
|
||||||
|
|
||||||
|
$languageId = (int)($request->getAttribute('language')?->getLanguageId() ?? 0);
|
||||||
|
$pageId = (int)($request->getAttribute('frontend.page.information')?->getId() ?? 0);
|
||||||
|
|
||||||
|
$typoScriptConfiguration = GeneralUtility::makeInstance(ConfigurationManager::class)
|
||||||
|
->getTypoScriptFromRequest($request);
|
||||||
|
if (!empty($contentElement['pi_flexform'])) {
|
||||||
|
GeneralUtility::makeInstance(ConfigurationService::class)->overrideConfigurationWithFlexFormSettings(
|
||||||
|
(string)$contentElement['pi_flexform'],
|
||||||
|
$typoScriptConfiguration,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$connection = GeneralUtility::makeInstance(ConnectionManager::class)
|
||||||
|
->getConnectionByTypo3Site($request->getAttribute('site'), $languageId);
|
||||||
|
$search = GeneralUtility::makeInstance(Search::class, $connection);
|
||||||
|
$searchService = GeneralUtility::makeInstance(
|
||||||
|
SearchResultSetService::class,
|
||||||
|
$typoScriptConfiguration,
|
||||||
|
$search,
|
||||||
|
);
|
||||||
|
$searchRequest = GeneralUtility::makeInstance(SearchRequestBuilder::class, $typoScriptConfiguration)
|
||||||
|
->buildForSearch(['q' => $query, 'page' => $page], $pageId, $languageId);
|
||||||
|
|
||||||
|
$resultSet = $searchService->search($searchRequest);
|
||||||
|
|
||||||
|
$highlighted = null;
|
||||||
|
try {
|
||||||
|
$highlighted = $resultSet->getUsedSearch()?->getHighlightedContent();
|
||||||
|
} catch (\Throwable) {
|
||||||
|
// no highlighting available - the excerpt fallback below covers it
|
||||||
|
}
|
||||||
|
|
||||||
|
$results = [];
|
||||||
|
foreach ($resultSet->getSearchResults() as $document) {
|
||||||
|
$id = (string)$document->getId();
|
||||||
|
if ($highlighted !== null && !empty($highlighted->{$id}->content[0])) {
|
||||||
|
$teaser = implode(' ... ', $highlighted->{$id}->content);
|
||||||
|
} else {
|
||||||
|
$teaser = mb_substr(trim((string)$document->getContent()), 0, self::TEASER_FALLBACK_LENGTH);
|
||||||
|
}
|
||||||
|
$results[] = [
|
||||||
|
'title' => (string)$document->getTitle(),
|
||||||
|
'url' => (string)$document->getUrl(),
|
||||||
|
'type' => (string)$document->getType(),
|
||||||
|
'teaser' => $teaser,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$suggestions = [];
|
||||||
|
try {
|
||||||
|
foreach ($resultSet->getSpellCheckingSuggestions() as $suggestion) {
|
||||||
|
$word = method_exists($suggestion, 'getSuggestion')
|
||||||
|
? (string)$suggestion->getSuggestion()
|
||||||
|
: '';
|
||||||
|
if ($word !== '') {
|
||||||
|
$suggestions[] = $word;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (\Throwable) {
|
||||||
|
// spellchecking disabled or unavailable - not essential
|
||||||
|
}
|
||||||
|
|
||||||
|
$numFound = $resultSet->getAllResultCount();
|
||||||
|
$resultsPerPage = $resultSet->getUsedResultsPerPage() ?: count($results);
|
||||||
|
|
||||||
|
return (string)json_encode([
|
||||||
|
'query' => $query,
|
||||||
|
'page' => $page,
|
||||||
|
'resultsPerPage' => $resultsPerPage,
|
||||||
|
'numFound' => $numFound,
|
||||||
|
'totalPages' => $resultsPerPage > 0 ? (int)ceil($numFound / $resultsPerPage) : 0,
|
||||||
|
'results' => $results,
|
||||||
|
'suggestions' => array_values(array_unique($suggestions)),
|
||||||
|
]);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string,mixed>
|
||||||
|
*/
|
||||||
|
private function emptyResult(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'query' => '',
|
||||||
|
'page' => 1,
|
||||||
|
'resultsPerPage' => 0,
|
||||||
|
'numFound' => 0,
|
||||||
|
'totalPages' => 0,
|
||||||
|
'results' => [],
|
||||||
|
'suggestions' => [],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
config {
|
config {
|
||||||
|
# EXT:solr indexes pages only when indexing is explicitly enabled
|
||||||
|
index_enable = 1
|
||||||
pageTitleProviders {
|
pageTitleProviders {
|
||||||
vitec {
|
vitec {
|
||||||
provider = Evomedien\Vitec\PageTitle\ProductPageTitleProvider
|
provider = Evomedien\Vitec\PageTitle\ProductPageTitleProvider
|
||||||
@@ -32,6 +34,19 @@ tt_content {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# EXT:solr search results as JSON - the search endpoint for the React frontend
|
||||||
|
solr_pi_results < lib.contentElementWithHeader
|
||||||
|
solr_pi_results {
|
||||||
|
fields {
|
||||||
|
content {
|
||||||
|
fields {
|
||||||
|
search = USER
|
||||||
|
search.userFunc = Evomedien\Vitec\UserFunc\SearchJsonRenderer->render
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
news_pi1 < lib.contentElementWithHeader
|
news_pi1 < lib.contentElementWithHeader
|
||||||
news_pi1 {
|
news_pi1 {
|
||||||
fields {
|
fields {
|
||||||
@@ -278,3 +293,46 @@ config.recordLinks {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Highlighted teaser fragments for the JSON search results (SearchJsonRenderer)
|
||||||
|
plugin.tx_solr.search.results.resultsHighlighting = 1
|
||||||
|
plugin.tx_solr.search.results.resultsHighlighting.wrap = <mark>|</mark>
|
||||||
|
|
||||||
|
|
||||||
|
# Headless has no TYPO3SEARCH_begin/end markers in its JSON output, so the
|
||||||
|
# default page content extraction indexes an EMPTY content field. Build the
|
||||||
|
# content from the page's tt_content rows instead: header, subheader, bodytext
|
||||||
|
# cover core CTypes and the Content Blocks (their text fields reuse bodytext),
|
||||||
|
# vitec_quote is the only Content Blocks text column of its own. SOLR_CONTENT
|
||||||
|
# strips markup before indexing. Collection children (FAQ items, cards) live in
|
||||||
|
# their own tables and are not covered yet.
|
||||||
|
plugin.tx_solr.index.queue.pages.fields {
|
||||||
|
content = SOLR_CONTENT
|
||||||
|
content {
|
||||||
|
cObject = COA
|
||||||
|
cObject {
|
||||||
|
10 = CONTENT
|
||||||
|
10 {
|
||||||
|
table = tt_content
|
||||||
|
select {
|
||||||
|
orderBy = sorting
|
||||||
|
}
|
||||||
|
renderObj = COA
|
||||||
|
renderObj {
|
||||||
|
10 = TEXT
|
||||||
|
10.field = header
|
||||||
|
10.noTrimWrap = || |
|
||||||
|
20 = TEXT
|
||||||
|
20.field = subheader
|
||||||
|
20.noTrimWrap = || |
|
||||||
|
30 = TEXT
|
||||||
|
30.field = bodytext
|
||||||
|
30.noTrimWrap = || |
|
||||||
|
40 = TEXT
|
||||||
|
40.field = vitec_quote
|
||||||
|
40.noTrimWrap = || |
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -250,3 +250,10 @@ $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeRegistry'][1750000000] = [
|
|||||||
);
|
);
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
// The JSON search endpoint (SearchJsonRenderer) uses plain `q` and `page` GET
|
||||||
|
// parameters. Without this exclusion TYPO3 demands a cHash for them and answers
|
||||||
|
// with an error page; the no_cache condition in the Vitecset TypoScript makes
|
||||||
|
// sure search responses are rendered fresh instead of sticking in the page cache.
|
||||||
|
$GLOBALS['TYPO3_CONF_VARS']['FE']['cacheHash']['excludedParameters'][] = 'q';
|
||||||
|
$GLOBALS['TYPO3_CONF_VARS']['FE']['cacheHash']['excludedParameters'][] = 'page';
|
||||||
|
|||||||
Reference in New Issue
Block a user