zwischenstand

This commit is contained in:
Sven Wappler
2021-04-29 18:33:05 +02:00
parent 2c9e27b3b7
commit 0ee2fae261
264 changed files with 263 additions and 21253 deletions

View File

@@ -1,50 +0,0 @@
<?php
namespace WapplerSystems\Meilisearch\System\Meilisearch\Document;
/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
use RuntimeException;
/**
* Document representing the update query document
*
* @author Timo Hund <timo.hund@dkd.de>
*/
class Document
{
/**
* Magic call method used to emulate getters as used by the template engine.
*
* @param string $name method name
* @param array $arguments method arguments
* @return mixed
*/
public function __call($name, $arguments)
{
if (substr($name, 0, 3) === 'get') {
$field = substr($name, 3);
$field = strtolower($field[0]) . substr($field, 1);
return $this->fields[$field] ?? null;
}
throw new RuntimeException('Call to undefined method. Supports magic getters only.', 1311006605);
}
/**
* @return array
*/
public function getFieldNames()
{
return array_keys($this->fields);
}
}

View File

@@ -30,9 +30,7 @@ use WapplerSystems\Meilisearch\System\Logging\MeilisearchLogManager;
use WapplerSystems\Meilisearch\System\Meilisearch\Parser\SchemaParser;
use WapplerSystems\Meilisearch\System\Meilisearch\Parser\StopWordParser;
use WapplerSystems\Meilisearch\System\Meilisearch\Parser\SynonymParser;
use WapplerSystems\Meilisearch\System\Meilisearch\Service\MeilisearchAdminService;
use WapplerSystems\Meilisearch\System\Meilisearch\Service\MeilisearchReadService;
use WapplerSystems\Meilisearch\System\Meilisearch\Service\MeilisearchWriteService;
use WapplerSystems\Meilisearch\System\Meilisearch\Service\MeilisearchService;
use WapplerSystems\Meilisearch\Util;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
@@ -50,19 +48,9 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
class MeilisearchConnection
{
/**
* @var MeilisearchAdminService
* @var MeilisearchService
*/
protected $adminService;
/**
* @var MeilisearchReadService
*/
protected $readService;
/**
* @var MeilisearchWriteService
*/
protected $writeService;
protected $service;
/**
* @var TypoScriptConfiguration
@@ -157,66 +145,24 @@ class MeilisearchConnection
/**
* @return MeilisearchAdminService
* @return MeilisearchService
*/
public function getAdminService(): MeilisearchAdminService
public function getService(): MeilisearchService
{
if ($this->adminService === null) {
$this->adminService = $this->buildAdminService();
if ($this->service === null) {
$this->service = $this->buildService();
}
return $this->adminService;
return $this->service;
}
/**
* @return MeilisearchAdminService
* @return MeilisearchService
* @noinspection PhpIncompatibleReturnTypeInspection
*/
protected function buildAdminService(): MeilisearchAdminService
protected function buildService(): MeilisearchService
{
return GeneralUtility::makeInstance(MeilisearchAdminService::class, $this, $this->client, $this->configuration, $this->logger, $this->synonymParser, $this->stopWordParser, $this->schemaParser);
}
/**
* @return MeilisearchReadService
*/
public function getReadService(): MeilisearchReadService
{
if ($this->readService === null) {
$this->readService = $this->buildReadService();
}
return $this->readService;
}
/**
* @return MeilisearchReadService
* @noinspection PhpIncompatibleReturnTypeInspection
*/
protected function buildReadService(): MeilisearchReadService
{
return GeneralUtility::makeInstance(MeilisearchReadService::class, $this->client);
}
/**
* @return MeilisearchWriteService
*/
public function getWriteService(): MeilisearchWriteService
{
if ($this->writeService === null) {
$this->writeService = $this->buildWriteService();
}
return $this->writeService;
}
/**
* @return MeilisearchWriteService
* @noinspection PhpIncompatibleReturnTypeInspection
*/
protected function buildWriteService(): MeilisearchWriteService
{
return GeneralUtility::makeInstance(MeilisearchWriteService::class, $this->client);
return GeneralUtility::makeInstance(MeilisearchService::class, $this, $this->client, $this->configuration, $this->logger, $this->synonymParser, $this->stopWordParser, $this->schemaParser);
}

View File

@@ -1,34 +0,0 @@
<?php
namespace WapplerSystems\Meilisearch\System\Meilisearch;
/**
* This class provides static helper functions that are helpful during the result parsing for meilisearch.
*/
class ParsingUtil
{
/**
* This method is used to covert a array structure with json.nl=flat to have it as return with json.nl=map.
*
* @param $options
* @return array
*/
public static function getMapArrayFromFlatArray(array $options): array
{
$keyValueMap = [];
$valueFromKeyNode = -1;
foreach($options as $key => $value) {
$isKeyNode = (($key % 2) == 0);
if ($isKeyNode) {
$valueFromKeyNode = $value;
} else {
if($valueFromKeyNode == -1) {
throw new \UnexpectedValueException('No optionValue before count value');
}
//we have a countNode
$keyValueMap[$valueFromKeyNode] = $value;
}
}
return $keyValueMap;
}
}

View File

@@ -1,44 +0,0 @@
<?php
declare(strict_types=1);
/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
namespace WapplerSystems\Meilisearch\System\Meilisearch;
use GuzzleHttp\Client as GuzzleClient;
use Psr\Http\Message\ResponseInterface;
use TYPO3\CMS\Core\Http\RequestFactory as CoreRequestFactory;
use TYPO3\CMS\Core\Utility\GeneralUtility;
class RequestFactory extends CoreRequestFactory
{
protected $clientOptions = [];
/**
* RequestFactory constructor.
* @param array $clientOptions
*/
public function __construct(array $clientOptions)
{
$this->clientOptions = $clientOptions;
}
public function request(string $uri, string $method = 'GET', array $options = []): ResponseInterface
{
/* @var GuzzleClient $client */
$client = GeneralUtility::makeInstance(GuzzleClient::class, $this->clientOptions);
return $client->request($method, $uri, $options);
}
}

View File

@@ -1,150 +0,0 @@
<?php
namespace WapplerSystems\Meilisearch\System\Meilisearch;
use WapplerSystems\Meilisearch\System\Meilisearch\Document\Document;
use Countable;
/**
* In EXT:meilisearch 9 we have switched from the MeilisearchPhpClient to the solarium api.
*
* In many places of the code the class Apache_Meilisearch_Response and the property Apache_Meilisearch_Response::reponse is used.
* To be able to refactor this we need to have a replacement for Apache_Meilisearch_Response that behaves like the original class,
* to keep the old code working. This allows us to drop the old code of MeilisearchPhpClient and refactore the other parts step by step.
*
* Class ResponseAdapter
*
* Search response
*
* @property \stdClass facet_counts
* @property \stdClass facets
* @property \stdClass spellcheck
* @property \stdClass response
* @property \stdClass responseHeader
* @property \stdClass highlighting
* @property \stdClass debug
* @property \stdClass lucene
* @property string file
* @property array file_metadata
*
* Luke response
*
* @property \stdClass index
* @property \stdClass fields
*/
class ResponseAdapter implements Countable
{
/**
* @var string
*/
protected $responseBody;
/**
* @var \stdClass
*/
protected $data = null;
/**
* @var int
*/
protected $httpStatus = 200;
/**
* @var string
*/
protected $httpStatusMessage = '';
/**
* ResponseAdapter constructor.
*
* @param string $responseBody
* @param int $httpStatus
* @param string $httpStatusMessage
*/
public function __construct($responseBody, $httpStatus = 500, $httpStatusMessage = '')
{
$this->data = json_decode($responseBody);
$this->responseBody = $responseBody;
$this->httpStatus = $httpStatus;
$this->httpStatusMessage = $httpStatusMessage;
// @extensionScannerIgnoreLine
if (isset($this->data->response) && is_array($this->data->response->docs)) {
$documents = array();
// @extensionScannerIgnoreLine
foreach ($this->data->response->docs as $originalDocument) {
$fields = get_object_vars($originalDocument);
$document = new Document($fields);
$documents[] = $document;
}
// @extensionScannerIgnoreLine
$this->data->response->docs = $documents;
}
}
/**
* Magic get to expose the parsed data and to lazily load it
*
* @param string $key
* @return mixed
*/
public function __get($key)
{
if (isset($this->data->$key)) {
return $this->data->$key;
}
return null;
}
/**
* Magic function for isset function on parsed data
*
* @param string $key
* @return boolean
*/
public function __isset($key)
{
return isset($this->data->$key);
}
/**
* @return mixed
*/
public function getParsedData()
{
return $this->data;
}
/**
* @return string
*/
public function getRawResponse()
{
return $this->responseBody;
}
/**
* @return int
*/
public function getHttpStatus(): int
{
return $this->httpStatus;
}
/**
* @return string
*/
public function getHttpStatusMessage(): string
{
return $this->httpStatusMessage;
}
/**
* Counts the elements of
*/
public function count()
{
return count(get_object_vars($this->data));
}
}

View File

@@ -29,7 +29,6 @@ use MeiliSearch\Exceptions\CommunicationException;
use WapplerSystems\Meilisearch\System\Configuration\TypoScriptConfiguration;
use WapplerSystems\Meilisearch\System\Logging\MeilisearchLogManager;
use WapplerSystems\Meilisearch\System\Meilisearch\MeilisearchConnection;
use WapplerSystems\Meilisearch\System\Meilisearch\ResponseAdapter;
use WapplerSystems\Meilisearch\Util;
use TYPO3\CMS\Core\Utility\GeneralUtility;
@@ -93,15 +92,14 @@ abstract class AbstractMeilisearchService
{
$siteConfiguration = $this->meilisearchConnection->getSiteConfiguration();
$strConnection = $siteConfiguration['schema'].$siteConfiguration['host'];
$strConnection = $siteConfiguration['scheme'].'://'.$siteConfiguration['host'].':'.$siteConfiguration['port'];
if (!$this->ping()) return $strConnection;
return $strConnection . ', ' . implode(',',$this->client->version());
return $strConnection . ', Version: ' . $this->client->version()['pkgVersion'];
}
/**
* Build the log data and writes the message to the log
*

View File

@@ -1,98 +0,0 @@
<?php
namespace WapplerSystems\Meilisearch\System\Meilisearch\Service;
/***************************************************************
* Copyright notice
*
* (c) 2009-2017 Timo Hund <timo.hund@dkd.de>
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
use WapplerSystems\Meilisearch\System\Meilisearch\ResponseAdapter;
use WapplerSystems\Meilisearch\System\Meilisearch\MeilisearchCommunicationException;
use WapplerSystems\Meilisearch\System\Meilisearch\MeilisearchInternalServerErrorException;
use WapplerSystems\Meilisearch\System\Meilisearch\MeilisearchUnavailableException;
/**
* Class MeilisearchReadService
*/
class MeilisearchReadService extends AbstractMeilisearchService
{
/**
* @var bool
*/
protected $hasSearched = false;
/**
* @var ResponseAdapter
*/
protected $responseCache = null;
/**
* Returns whether a search has been executed or not.
*
* @return bool TRUE if a search has been executed, FALSE otherwise
*/
public function hasSearched()
{
return $this->hasSearched;
}
/**
* Gets the most recent response (if any)
*
* @return ResponseAdapter Most recent response, or NULL if a search has not been executed yet.
*/
public function getResponse()
{
return $this->responseCache;
}
/**
* This method maps the failed meilisearch requests to a meaningful exception.
*
* @param HttpException $exception
* @throws MeilisearchCommunicationException
* @return HttpException
*/
protected function handleErrorResponses(HttpException $exception)
{
$status = $exception->getCode();
$message = $exception->getStatusMessage();
$meilisearchRespone = new ResponseAdapter($exception->getBody());
if ($status === 0 || $status === 502) {
$e = new MeilisearchUnavailableException('Meilisearch Server not available: ' . $message, 1505989391);
$e->setMeilisearchResponse($meilisearchRespone);
throw $e;
}
if ($status === 500) {
$e = new MeilisearchInternalServerErrorException('Internal Server error during search: ' . $message, 1505989897);
$e->setMeilisearchResponse($meilisearchRespone);
throw $e;
}
$e = new MeilisearchCommunicationException('Invalid query. Meilisearch returned an error: ' . $status . ' ' . $message, 1293109870);
$e->setMeilisearchResponse($meilisearchRespone);
throw $e;
}
}

View File

@@ -31,14 +31,13 @@ use WapplerSystems\Meilisearch\System\Meilisearch\MeilisearchConnection;
use WapplerSystems\Meilisearch\System\Meilisearch\Parser\SchemaParser;
use WapplerSystems\Meilisearch\System\Meilisearch\Parser\StopWordParser;
use WapplerSystems\Meilisearch\System\Meilisearch\Parser\SynonymParser;
use WapplerSystems\Meilisearch\System\Meilisearch\ResponseAdapter;
use WapplerSystems\Meilisearch\System\Meilisearch\Schema\Schema;
use TYPO3\CMS\Core\Utility\GeneralUtility;
/**
* Class MeilisearchAdminService
*/
class MeilisearchAdminService extends AbstractMeilisearchService
class MeilisearchService extends AbstractMeilisearchService
{
protected $systemData = null;
@@ -101,25 +100,6 @@ class MeilisearchAdminService extends AbstractMeilisearchService
}
/**
* Gets information about the Meilisearch server
*
* @return ResponseAdapter
*/
public function getSystemInformation()
{
if (empty($this->systemData)) {
$systemInformation = $this->system();
// access a random property to trigger response parsing
$this->systemData = $systemInformation;
}
return $this->systemData;
}
/**
* Get currently configured synonyms
*

View File

@@ -1,120 +0,0 @@
<?php
namespace WapplerSystems\Meilisearch\System\Meilisearch\Service;
/***************************************************************
* Copyright notice
*
* (c) 2009-2017 Timo Hund <timo.hund@dkd.de>
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
use WapplerSystems\Meilisearch\System\Logging\MeilisearchLogManager;
use WapplerSystems\Meilisearch\System\Meilisearch\ResponseAdapter;
/**
* Class MeilisearchWriteService
*/
class MeilisearchWriteService extends AbstractMeilisearchService
{
const EXTRACT_SERVLET = 'update/extract';
/**
* Performs a content and meta data extraction request.
*
* @param Query $query An extraction query
* @return array An array containing the extracted content [0] and meta data [1]
*/
public function extractByQuery(Query $query)
{
try {
$response = $this->createAndExecuteRequest($query);
return [$response->file, (array)$response->file_metadata];
} catch (\Exception $e) {
$param = $query->getRequestBuilder()->build($query)->getParams();
$this->logger->log(
MeilisearchLogManager::ERROR,
'Extracting text and meta data through Meilisearch Cell over HTTP POST',
[
'query' => (array)$query,
'parameters' => $param,
'file' => $query->getFile(),
'query url' => self::EXTRACT_SERVLET,
'exception' => $e->getMessage()
]
);
}
return [];
}
/**
* Deletes all index documents of a certain type and does a commit
* afterwards.
*
* @param string $type The type of documents to delete, usually a table name.
* @param bool $commit Will commit immediately after deleting the documents if set, defaults to TRUE
*/
public function deleteByType($type, $commit = true)
{
$this->deleteByQuery('type:' . trim($type));
if ($commit) {
$this->commit(false, false);
}
}
/**
* Create a delete document based on a query and submit it
*
* @param string $rawQuery Expected to be utf-8 encoded
* @return ResponseAdapter
*/
public function deleteByQuery($rawQuery) {
$query = $this->client->createUpdate();
$query->addDeleteQuery($rawQuery);
return $this->createAndExecuteRequest($query);
}
/**
* Add an array of Meilisearch Documents to the index all at once
*
* @param array $documents Should be an array of \WapplerSystems\Meilisearch\System\Meilisearch\Document\Document instances
* @return ResponseAdapter
*/
public function addDocuments($documents)
{
$update = $this->client->createUpdate();
$update->addDocuments($documents);
return $this->createAndExecuteRequest($update);
}
/**
* Send a commit command. Will be synchronous unless both wait parameters are set to false.
*
* @param boolean $expungeDeletes Defaults to false, merge segments with deletes away
* @param boolean $waitSearcher Defaults to true, block until a new searcher is opened and registered as the main query searcher, making the changes visible
* @return ResponseAdapter
*/
public function commit($expungeDeletes = false, $waitSearcher = true)
{
$update = $this->client->createUpdate();
$update->addCommit(false, $waitSearcher, $expungeDeletes);
return $this->createAndExecuteRequest($update);
}
}