mirror of
https://github.com/Codappix/search_core.git
synced 2024-11-21 21:56:10 +01:00
Merge remote-tracking branch 'origin/develop' into feature/phpcs-travis
Conflicts: Classes/Hook/DataHandler.php
This commit is contained in:
commit
ae51de9041
34 changed files with 437 additions and 269 deletions
|
@ -11,6 +11,7 @@ before_install:
|
|||
language: php
|
||||
|
||||
php:
|
||||
- 7.0
|
||||
- 7.1
|
||||
|
||||
env:
|
||||
|
|
|
@ -45,25 +45,26 @@ class Facet implements FacetInterface
|
|||
*/
|
||||
protected $options = [];
|
||||
|
||||
public function __construct($name, array $aggregation, ConfigurationContainerInterface $configuration)
|
||||
public function __construct(string $name, array $aggregation, ConfigurationContainerInterface $configuration)
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->buckets = $aggregation['buckets'];
|
||||
$this->field = $configuration->getIfExists('searching.facets.' . $this->name . '.field') ?: '';
|
||||
|
||||
$config = $configuration->getIfExists('searching.facets.' . $this->name) ?: [];
|
||||
foreach ($config as $configEntry) {
|
||||
if (isset($configEntry['field'])) {
|
||||
$this->field = $configEntry['field'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
public function getName() : string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getField()
|
||||
public function getField() : string
|
||||
{
|
||||
return $this->field;
|
||||
}
|
||||
|
@ -73,7 +74,7 @@ class Facet implements FacetInterface
|
|||
*
|
||||
* @return array<FacetOptionInterface>
|
||||
*/
|
||||
public function getOptions()
|
||||
public function getOptions() : array
|
||||
{
|
||||
$this->initOptions();
|
||||
|
||||
|
|
|
@ -28,15 +28,11 @@ interface FacetRequestInterface
|
|||
/**
|
||||
* The identifier of the facet, used as key in arrays and to get the facet
|
||||
* from search request, etc.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getIdentifier();
|
||||
public function getIdentifier() : string;
|
||||
|
||||
/**
|
||||
* The field to use for facet building.
|
||||
*
|
||||
* @return string
|
||||
* The config to use for facet building.
|
||||
*/
|
||||
public function getField();
|
||||
public function getConfig() : array;
|
||||
}
|
||||
|
|
|
@ -48,6 +48,12 @@ abstract class AbstractIndexer implements IndexerInterface
|
|||
*/
|
||||
protected $logger;
|
||||
|
||||
/**
|
||||
* @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface
|
||||
* @inject
|
||||
*/
|
||||
protected $objectManager;
|
||||
|
||||
/**
|
||||
* Inject log manager to get concrete logger from it.
|
||||
*
|
||||
|
@ -141,7 +147,8 @@ abstract class AbstractIndexer implements IndexerInterface
|
|||
} else {
|
||||
$className = $configuration['_typoScriptNodeValue'];
|
||||
}
|
||||
$dataProcessor = GeneralUtility::makeInstance($className);
|
||||
|
||||
$dataProcessor = $this->objectManager->get($className);
|
||||
if ($dataProcessor instanceof ProcessorInterface) {
|
||||
$record = $dataProcessor->processRecord($record, $configuration);
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ namespace Codappix\SearchCore\Domain\Index\TcaIndexer;
|
|||
* 02110-1301, USA.
|
||||
*/
|
||||
|
||||
use Codappix\SearchCore\Utility\FrontendUtility;
|
||||
use TYPO3\CMS\Backend\Utility\BackendUtility;
|
||||
use TYPO3\CMS\Core\SingletonInterface as Singleton;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
@ -32,20 +33,22 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
|
|||
*/
|
||||
class RelationResolver implements Singleton
|
||||
{
|
||||
public function resolveRelationsForRecord(TcaTableService $service, array &$record) : void
|
||||
public function resolveRelationsForRecord(TcaTableService $service, array &$record)
|
||||
{
|
||||
foreach (array_keys($record) as $column) {
|
||||
// TODO: Define / configure fields to exclude?!
|
||||
if ($column === 'pid') {
|
||||
continue;
|
||||
}
|
||||
$record[$column] = BackendUtility::getProcessedValueExtra(
|
||||
$service->getTableName(),
|
||||
$column,
|
||||
$record[$column],
|
||||
0,
|
||||
$record['uid']
|
||||
);
|
||||
|
||||
$record[$column] = GeneralUtility::makeInstance($this->getUtilityForMode())
|
||||
::getProcessedValueExtra(
|
||||
$service->getTableName(),
|
||||
$column,
|
||||
$record[$column],
|
||||
0,
|
||||
$record['uid']
|
||||
);
|
||||
|
||||
try {
|
||||
$config = $service->getColumnConfig($column);
|
||||
|
@ -93,4 +96,13 @@ class RelationResolver implements Singleton
|
|||
{
|
||||
return array_map('trim', explode(',', $value));
|
||||
}
|
||||
|
||||
protected function getUtilityForMode(): string
|
||||
{
|
||||
if (TYPO3_MODE === 'BE') {
|
||||
return BackendUtility::class;
|
||||
}
|
||||
|
||||
return FrontendUtility::class;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -129,7 +129,7 @@ class TcaTableService
|
|||
* @param array &$records
|
||||
* @return void
|
||||
*/
|
||||
public function filterRecordsByRootLineBlacklist(array &$records) : void
|
||||
public function filterRecordsByRootLineBlacklist(array &$records)
|
||||
{
|
||||
$records = array_filter(
|
||||
$records,
|
||||
|
@ -142,7 +142,7 @@ class TcaTableService
|
|||
/**
|
||||
* @param array &$record
|
||||
*/
|
||||
public function prepareRecord(array &$record) : void
|
||||
public function prepareRecord(array &$record)
|
||||
{
|
||||
$this->relationResolver->resolveRelationsForRecord($this, $record);
|
||||
|
||||
|
|
|
@ -30,37 +30,27 @@ class FacetRequest implements FacetRequestInterface
|
|||
protected $identifier = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @var array
|
||||
*/
|
||||
protected $field = '';
|
||||
protected $config = [];
|
||||
|
||||
/**
|
||||
* TODO: Add validation / exception?
|
||||
* As the facets come from configuration this might be a good idea to help
|
||||
* integrators find issues.
|
||||
*
|
||||
* @param string $identifier
|
||||
* @param string $field
|
||||
*/
|
||||
public function __construct($identifier, $field)
|
||||
public function __construct(string $identifier, array $config)
|
||||
{
|
||||
$this->identifier = $identifier;
|
||||
$this->field = $field;
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getIdentifier()
|
||||
public function getIdentifier() : string
|
||||
{
|
||||
return $this->identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getField()
|
||||
public function getConfig() : array
|
||||
{
|
||||
return $this->field;
|
||||
return $this->config;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -99,20 +99,18 @@ class QueryFactory
|
|||
return;
|
||||
}
|
||||
|
||||
$query = ArrayUtility::setValueByPath(
|
||||
$query,
|
||||
'query.bool.must.0.match._all.query',
|
||||
$searchRequest->getSearchTerm()
|
||||
);
|
||||
$matchExpression = [
|
||||
'type' => 'most_fields',
|
||||
'query' => $searchRequest->getSearchTerm(),
|
||||
'fields' => GeneralUtility::trimExplode(',', $this->configuration->get('searching.fields.query')),
|
||||
];
|
||||
|
||||
$minimumShouldMatch = $this->configuration->getIfExists('searching.minimumShouldMatch');
|
||||
if ($minimumShouldMatch) {
|
||||
$query = ArrayUtility::setValueByPath(
|
||||
$query,
|
||||
'query.bool.must.0.match._all.minimum_should_match',
|
||||
$minimumShouldMatch
|
||||
);
|
||||
$matchExpression['minimum_should_match'] = $minimumShouldMatch;
|
||||
}
|
||||
|
||||
$query = ArrayUtility::setValueByPath($query, 'query.bool.must.0.multi_match', $matchExpression);
|
||||
}
|
||||
|
||||
protected function addBoosts(SearchRequestInterface $searchRequest, array &$query)
|
||||
|
@ -248,11 +246,7 @@ class QueryFactory
|
|||
foreach ($searchRequest->getFacets() as $facet) {
|
||||
$query = ArrayUtility::arrayMergeRecursiveOverrule($query, [
|
||||
'aggs' => [
|
||||
$facet->getIdentifier() => [
|
||||
'terms' => [
|
||||
'field' => $facet->getField(),
|
||||
],
|
||||
],
|
||||
$facet->getIdentifier() => $facet->getConfig(),
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
|
|
@ -103,15 +103,10 @@ class SearchService
|
|||
}
|
||||
|
||||
foreach ($facetsConfig as $identifier => $facetConfig) {
|
||||
if (!isset($facetConfig['field']) || trim($facetConfig['field']) === '') {
|
||||
// TODO: Finish throw
|
||||
throw new \Exception('message', 1499171142);
|
||||
}
|
||||
|
||||
$searchRequest->addFacet($this->objectManager->get(
|
||||
FacetRequest::class,
|
||||
$identifier,
|
||||
$facetConfig['field']
|
||||
$facetConfig
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -83,16 +83,6 @@ class DataHandler implements Singleton
|
|||
$this->indexerFactory = $indexerFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $table
|
||||
* @param array $record
|
||||
*/
|
||||
public function add($table, array $record)
|
||||
{
|
||||
$this->logger->debug('Record received for add.', [$table, $record]);
|
||||
$this->getIndexer($table)->indexDocument($record['uid']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $table
|
||||
*/
|
||||
|
|
|
@ -92,47 +92,36 @@ class DataHandler implements Singleton
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by CoreDataHandler on database operations, e.g. if new records were created or records were updated.
|
||||
*
|
||||
* @param string $status
|
||||
* @param string $table
|
||||
* @param string|int $uid
|
||||
* @param array $fieldArray
|
||||
* @param CoreDataHandler $dataHandler
|
||||
*
|
||||
* @return bool False if hook was not processed.
|
||||
*/
|
||||
public function processDatamap_afterDatabaseOperations(
|
||||
$status,
|
||||
$table,
|
||||
$uid,
|
||||
array $fieldArray,
|
||||
CoreDataHandler $dataHandler
|
||||
) {
|
||||
public function processDatamap_afterAllOperations(CoreDataHandler $dataHandler)
|
||||
{
|
||||
foreach ($dataHandler->datamap as $table => $record) {
|
||||
$uid = key($record);
|
||||
$fieldData = current($record);
|
||||
|
||||
if (isset($fieldArray['uid'])) {
|
||||
$uid = $fieldArray['uid'];
|
||||
} elseif (isset($dataHandler->substNEWwithIDs[$uid])) {
|
||||
$uid = $dataHandler->substNEWwithIDs[$uid];
|
||||
}
|
||||
|
||||
$this->processRecord($table, $uid);
|
||||
}
|
||||
}
|
||||
|
||||
protected function processRecord(string $table, int $uid) : bool
|
||||
{
|
||||
if (! $this->shouldProcessHookForTable($table)) {
|
||||
$this->logger->debug('Database update not processed.', [$table, $uid]);
|
||||
$this->logger->debug('Indexing of record not processed.', [$table, $uid]);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($status === 'new') {
|
||||
$fieldArray['uid'] = $dataHandler->substNEWwithIDs[$uid];
|
||||
$this->dataHandler->add($table, $fieldArray);
|
||||
$record = $this->getRecord($table, $uid);
|
||||
if ($record !== null) {
|
||||
$this->dataHandler->update($table, $record);
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($status === 'update') {
|
||||
$record = $this->getRecord($table, $uid);
|
||||
if ($record !== null) {
|
||||
$this->dataHandler->update($table, $record);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->logger->debug(
|
||||
'Database update not processed, cause status is unhandled.',
|
||||
[$status, $table, $uid, $fieldArray]
|
||||
);
|
||||
$this->logger->debug('Indexing of record not processed, as he was not found in Database.', [$table, $uid]);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -58,10 +58,8 @@ class DataHandlerFinisher extends AbstractFinisher
|
|||
|
||||
switch ($action) {
|
||||
case 'update':
|
||||
$this->dataHandler->update($tableName, $record);
|
||||
break;
|
||||
case 'add':
|
||||
$this->dataHandler->add($tableName, $record);
|
||||
$this->dataHandler->update($tableName, $record);
|
||||
break;
|
||||
case 'delete':
|
||||
$this->dataHandler->delete($tableName, $record['uid']);
|
||||
|
|
39
Classes/Utility/FrontendUtility.php
Normal file
39
Classes/Utility/FrontendUtility.php
Normal file
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
namespace Codappix\SearchCore\Utility;
|
||||
|
||||
/*
|
||||
* Copyright (C) 2018 Justus Moroni <developer@leonmrni.com>
|
||||
*
|
||||
* This program 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 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*/
|
||||
|
||||
use TYPO3\CMS\Backend\Utility\BackendUtility;
|
||||
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
|
||||
|
||||
/**
|
||||
* Overwrite BackendUtility to use in frontend.
|
||||
* LanguageService was only usable in backend.
|
||||
*/
|
||||
class FrontendUtility extends BackendUtility
|
||||
{
|
||||
/**
|
||||
* @return TypoScriptFrontendController
|
||||
*/
|
||||
protected static function getLanguageService()
|
||||
{
|
||||
return $GLOBALS['TSFE'];
|
||||
}
|
||||
}
|
|
@ -21,6 +21,12 @@ plugin {
|
|||
abstractFields = {$plugin.tx_searchcore.settings.indexing.pages.abstractFields}
|
||||
}
|
||||
}
|
||||
|
||||
searching {
|
||||
fields {
|
||||
query = _all
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
8
Documentation/source/changelog.rst
Normal file
8
Documentation/source/changelog.rst
Normal file
|
@ -0,0 +1,8 @@
|
|||
Changelog
|
||||
=========
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:glob:
|
||||
|
||||
changelog/*
|
|
@ -0,0 +1,40 @@
|
|||
Breacking Change 120 "Pass facets configuration to elasticsearch"
|
||||
=================================================================
|
||||
|
||||
In order to allow arbitrary facet configuration, we do not process the facet configuration anymore.
|
||||
Instead integrators are able to configure facets for search service "as is". We just pipe the
|
||||
configuration through.
|
||||
|
||||
Therefore the following, which worked before, does not work anymore:
|
||||
|
||||
.. code-block:: typoscript
|
||||
:linenos:
|
||||
:emphasize-lines: 4
|
||||
|
||||
plugin.tx_searchcore.settings.search {
|
||||
facets {
|
||||
category {
|
||||
field = categories
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Instead you have to provide the full configuration yourself:
|
||||
|
||||
.. code-block:: typoscript
|
||||
:linenos:
|
||||
:emphasize-lines: 4,6
|
||||
|
||||
plugin.tx_searchcore.settings.search {
|
||||
facets {
|
||||
category {
|
||||
terms {
|
||||
field = categories
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
You need to add line 4 and 6, the additional level ``terms`` for elasticsearch.
|
||||
|
||||
See :issue:`120`.
|
|
@ -5,9 +5,12 @@
|
|||
Configuration
|
||||
=============
|
||||
|
||||
Installation wide configuration is handled inside of the extension manager. Just check out the
|
||||
options there, they all have labels.
|
||||
|
||||
The extension offers the following configuration options through TypoScript. If you overwrite them
|
||||
through `setup` make sure to keep them in the `module` area as they will be accessed from backend
|
||||
mode of TYPO3. Do so by placing the following line at the end::
|
||||
mode of TYPO3 for indexing. Do so by placing the following line at the end::
|
||||
|
||||
module.tx_searchcore < plugin.tx_searchcore
|
||||
|
||||
|
|
|
@ -205,3 +205,6 @@ class name) as done in the examples above.
|
|||
By implementing also the same interface as necessary for TYPO3
|
||||
:ref:`t3tsref:cobj-fluidtemplate-properties-dataprocessing`, you are able to reuse the same code
|
||||
also for Fluid to prepare the same record fetched from DB for your fluid.
|
||||
|
||||
Dependency injection is possible inside of processors, as we instantiate through extbase
|
||||
``ObjectManager``.
|
||||
|
|
|
@ -151,7 +151,18 @@ filtering. This way you can use arbitrary filter names and map them to existing
|
|||
fields
|
||||
------
|
||||
|
||||
Defines the fields to fetch from elasticsearch. Two sub entries exist:
|
||||
Defines the fields to fetch and search from elasticsearch. With the following sub keys:
|
||||
|
||||
``query`` defines the fields to search in. Default is ``_all`` from 5.x times of elasticsearch.
|
||||
Configure a comma separated list of fields to search in. This is necessary if you have configured
|
||||
special mapping for some fields, or just want to search some fields.
|
||||
The most hits get ranked highest. The following is an example configuration::
|
||||
|
||||
fields {
|
||||
query = _all, city
|
||||
}
|
||||
|
||||
The following sub properties configure the fields to fetch from elasticsearch:
|
||||
|
||||
First ``stored_fields`` which is a list of comma separated fields which actually exist and will be
|
||||
added. Typically you will use ``_source`` to fetch the whole indexed fields.
|
||||
|
|
|
@ -15,3 +15,4 @@ Table of Contents
|
|||
connections
|
||||
indexer
|
||||
development
|
||||
changelog
|
||||
|
|
|
@ -19,4 +19,8 @@ In that case you need to install all dependencies yourself. Dependencies are:
|
|||
Afterwards you need to enable the extension through the extension manager and include the static
|
||||
TypoScript setup.
|
||||
|
||||
If you **don't** want to use the included elasticsearch integration, you have to disable it in the
|
||||
extension manager configuration of the extension by checking the checkbox.
|
||||
It's currently enabled by default but will be moved into its own extension in the future.
|
||||
|
||||
.. _downloading: https://github.com/DanielSiepmann/search_core/archive/master.zip
|
||||
|
|
78
Tests/Functional/Connection/Elasticsearch/FacetTest.php
Normal file
78
Tests/Functional/Connection/Elasticsearch/FacetTest.php
Normal file
|
@ -0,0 +1,78 @@
|
|||
<?php
|
||||
namespace Codappix\SearchCore\Tests\Functional\Connection\Elasticsearch;
|
||||
|
||||
/*
|
||||
* Copyright (C) 2017 Daniel Siepmann <coding@daniel-siepmann.de>
|
||||
*
|
||||
* This program 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 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*/
|
||||
|
||||
use Codappix\SearchCore\Domain\Index\IndexerFactory;
|
||||
use Codappix\SearchCore\Domain\Model\SearchRequest;
|
||||
use Codappix\SearchCore\Domain\Search\SearchService;
|
||||
use TYPO3\CMS\Extbase\Object\ObjectManager;
|
||||
|
||||
class FacetTest extends AbstractFunctionalTestCase
|
||||
{
|
||||
protected function getTypoScriptFilesForFrontendRootPage()
|
||||
{
|
||||
return array_merge(
|
||||
parent::getTypoScriptFilesForFrontendRootPage(),
|
||||
['EXT:search_core/Tests/Functional/Fixtures/Searching/Facet.ts']
|
||||
);
|
||||
}
|
||||
|
||||
protected function getDataSets()
|
||||
{
|
||||
return array_merge(
|
||||
parent::getDataSets(),
|
||||
['Tests/Functional/Fixtures/Searching/Filter.xml']
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function itsPossibleToFetchFacetsForField()
|
||||
{
|
||||
\TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(ObjectManager::class)
|
||||
->get(IndexerFactory::class)
|
||||
->getIndexer('tt_content')
|
||||
->indexAllDocuments()
|
||||
;
|
||||
|
||||
$searchService = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(ObjectManager::class)
|
||||
->get(SearchService::class);
|
||||
|
||||
$searchRequest = new SearchRequest();
|
||||
$result = $searchService->search($searchRequest);
|
||||
|
||||
$this->assertSame(1, count($result->getFacets()), 'Did not receive the single defined facet.');
|
||||
|
||||
$facet = current($result->getFacets());
|
||||
$this->assertSame('contentTypes', $facet->getName(), 'Name of facet was not as expected.');
|
||||
$this->assertSame('CType', $facet->getField(), 'Field of facet was not expected.');
|
||||
|
||||
$options = $facet->getOptions();
|
||||
$this->assertSame(2, count($options), 'Did not receive the expected number of possible options for facet.');
|
||||
$option = $options['HTML'];
|
||||
$this->assertSame('HTML', $option->getName(), 'Option did not have expected Name.');
|
||||
$this->assertSame(1, $option->getCount(), 'Option did not have expected count.');
|
||||
$option = $options['Header'];
|
||||
$this->assertSame('Header', $option->getName(), 'Option did not have expected Name.');
|
||||
$this->assertSame(1, $option->getCount(), 'Option did not have expected count.');
|
||||
}
|
||||
}
|
|
@ -58,37 +58,4 @@ class FilterTest extends AbstractFunctionalTestCase
|
|||
$this->assertSame(5, $result->getResults()[0]['uid'], 'Did not get the expected result entry.');
|
||||
$this->assertSame(1, count($result), 'Did not receive the single filtered element.');
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function itsPossibleToFetchFacetsForField()
|
||||
{
|
||||
\TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(ObjectManager::class)
|
||||
->get(IndexerFactory::class)
|
||||
->getIndexer('tt_content')
|
||||
->indexAllDocuments()
|
||||
;
|
||||
|
||||
$searchService = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(ObjectManager::class)
|
||||
->get(SearchService::class);
|
||||
|
||||
$searchRequest = new SearchRequest('Search Word');
|
||||
$result = $searchService->search($searchRequest);
|
||||
|
||||
$this->assertSame(1, count($result->getFacets()), 'Did not receive the single defined facet.');
|
||||
|
||||
$facet = current($result->getFacets());
|
||||
$this->assertSame('contentTypes', $facet->getName(), 'Name of facet was not as expected.');
|
||||
$this->assertSame('CType', $facet->getField(), 'Field of facet was not expected.');
|
||||
|
||||
$options = $facet->getOptions();
|
||||
$this->assertSame(2, count($options), 'Did not receive the expected number of possible options for facet.');
|
||||
$option = $options['HTML'];
|
||||
$this->assertSame('HTML', $option->getName(), 'Option did not have expected Name.');
|
||||
$this->assertSame(1, $option->getCount(), 'Option did not have expected count.');
|
||||
$option = $options['Header'];
|
||||
$this->assertSame('Header', $option->getName(), 'Option did not have expected Name.');
|
||||
$this->assertSame(1, $option->getCount(), 'Option did not have expected count.');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,10 +37,8 @@ plugin {
|
|||
}
|
||||
|
||||
searching {
|
||||
facets {
|
||||
contentTypes {
|
||||
field = CType
|
||||
}
|
||||
fields {
|
||||
query = _all
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
17
Tests/Functional/Fixtures/Searching/Facet.ts
Normal file
17
Tests/Functional/Fixtures/Searching/Facet.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
plugin {
|
||||
tx_searchcore {
|
||||
settings {
|
||||
searching {
|
||||
facets {
|
||||
contentTypes {
|
||||
terms {
|
||||
field = CType
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.tx_searchcore < plugin.tx_searchcore
|
|
@ -1,54 +0,0 @@
|
|||
<?php
|
||||
namespace Codappix\SearchCore\Tests\Functional\Hooks\DataHandler;
|
||||
|
||||
/*
|
||||
* Copyright (C) 2016 Daniel Siepmann <coding@daniel-siepmann.de>
|
||||
*
|
||||
* This program 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 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*/
|
||||
|
||||
use Codappix\SearchCore\Configuration\ConfigurationContainerInterface;
|
||||
use Codappix\SearchCore\Domain\Service\DataHandler as DataHandlerService;
|
||||
use Codappix\SearchCore\Hook\DataHandler as DataHandlerHook;
|
||||
use TYPO3\CMS\Core\DataHandling\DataHandler as Typo3DataHandler;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Object\ObjectManager;
|
||||
|
||||
class IgnoresUnkownOperationTest extends AbstractDataHandlerTest
|
||||
{
|
||||
/**
|
||||
* @var DataHandlerService|\PHPUnit_Framework_MockObject_MockObject|AccessibleObjectInterface
|
||||
*/
|
||||
protected $subject;
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function dataHandlerCommandSomethingIsIgnored()
|
||||
{
|
||||
$subject = new DataHandlerHook($this->subject);
|
||||
$this->assertFalse(
|
||||
$subject->processDatamap_afterDatabaseOperations(
|
||||
'something',
|
||||
'tt_content',
|
||||
1,
|
||||
[],
|
||||
new Typo3DataHandler
|
||||
),
|
||||
'Hook processed status "something".'
|
||||
);
|
||||
}
|
||||
}
|
|
@ -64,7 +64,7 @@ class NonAllowedTablesTest extends AbstractDataHandlerTest
|
|||
/**
|
||||
* @test
|
||||
*/
|
||||
public function updateWillNotBeTriggeredForSysCategory()
|
||||
public function updateWillNotBeTriggeredForExistingSysCategory()
|
||||
{
|
||||
$this->subject->expects($this->exactly(0))->method('update');
|
||||
|
||||
|
@ -83,9 +83,9 @@ class NonAllowedTablesTest extends AbstractDataHandlerTest
|
|||
/**
|
||||
* @test
|
||||
*/
|
||||
public function addWillNotBeTriggeredForSysCategoy()
|
||||
public function updateWillNotBeTriggeredForNewSysCategoy()
|
||||
{
|
||||
$this->subject->expects($this->exactly(0))->method('add');
|
||||
$this->subject->expects($this->exactly(0))->method('update');
|
||||
|
||||
$tce = GeneralUtility::makeInstance(Typo3DataHandler::class);
|
||||
$tce->stripslashes_values = 0;
|
||||
|
|
|
@ -66,7 +66,7 @@ class ProcessesAllowedTablesTest extends AbstractDataHandlerTest
|
|||
/**
|
||||
* @test
|
||||
*/
|
||||
public function updateWillBeTriggeredForTtContent()
|
||||
public function updateWillBeTriggeredForExistingTtContent()
|
||||
{
|
||||
$this->subject->expects($this->exactly(1))->method('update')
|
||||
->with(
|
||||
|
@ -94,9 +94,9 @@ class ProcessesAllowedTablesTest extends AbstractDataHandlerTest
|
|||
/**
|
||||
* @test
|
||||
*/
|
||||
public function addWillBeTriggeredForTtContent()
|
||||
public function updateWillBeTriggeredForNewTtContent()
|
||||
{
|
||||
$this->subject->expects($this->exactly(1))->method('add')
|
||||
$this->subject->expects($this->exactly(1))->method('update')
|
||||
->with(
|
||||
$this->equalTo('tt_content'),
|
||||
$this->callback(function ($record) {
|
||||
|
|
|
@ -26,6 +26,7 @@ use Codappix\SearchCore\Connection\ConnectionInterface;
|
|||
use Codappix\SearchCore\DataProcessing\CopyToProcessor;
|
||||
use Codappix\SearchCore\Domain\Index\AbstractIndexer;
|
||||
use Codappix\SearchCore\Tests\Unit\AbstractUnitTestCase;
|
||||
use TYPO3\CMS\Extbase\Object\ObjectManagerInterface;
|
||||
|
||||
class AbstractIndexerTest extends AbstractUnitTestCase
|
||||
{
|
||||
|
@ -44,17 +45,25 @@ class AbstractIndexerTest extends AbstractUnitTestCase
|
|||
*/
|
||||
protected $connection;
|
||||
|
||||
/**
|
||||
* @var ObjectManagerInterface
|
||||
*/
|
||||
protected $objectManager;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->configuration = $this->getMockBuilder(ConfigurationContainerInterface::class)->getMock();
|
||||
$this->connection = $this->getMockBuilder(ConnectionInterface::class)->getMock();
|
||||
$this->objectManager = $this->getMockBuilder(ObjectManagerInterface::class)->getMock();
|
||||
|
||||
|
||||
$this->subject = $this->getMockForAbstractClass(AbstractIndexer::class, [
|
||||
$this->connection,
|
||||
$this->configuration
|
||||
]);
|
||||
$this->inject($this->subject, 'objectManager', $this->objectManager);
|
||||
$this->subject->injectLogger($this->getMockedLogger());
|
||||
$this->subject->setIdentifier('testTable');
|
||||
$this->subject->expects($this->any())
|
||||
|
@ -73,6 +82,11 @@ class AbstractIndexerTest extends AbstractUnitTestCase
|
|||
$expectedRecord['new_test_field2'] = 'test' . PHP_EOL . 'test';
|
||||
$expectedRecord['search_abstract'] = '';
|
||||
|
||||
$this->objectManager->expects($this->any())
|
||||
->method('get')
|
||||
->with(CopyToProcessor::class)
|
||||
->willReturn(new CopyToProcessor());
|
||||
|
||||
$this->configuration->expects($this->exactly(2))
|
||||
->method('get')
|
||||
->withConsecutive(['indexing.testTable.dataProcessing'], ['indexing.testTable.abstractFields'])
|
||||
|
|
|
@ -56,9 +56,7 @@ class QueryFactoryTest extends AbstractUnitTestCase
|
|||
{
|
||||
$searchRequest = new SearchRequest('SearchWord');
|
||||
|
||||
$this->configuration->expects($this->any())
|
||||
->method('get')
|
||||
->will($this->throwException(new InvalidArgumentException));
|
||||
$this->configureConfigurationMockWithDefault();
|
||||
|
||||
$query = $this->subject->create($searchRequest);
|
||||
$this->assertInstanceOf(
|
||||
|
@ -73,9 +71,7 @@ class QueryFactoryTest extends AbstractUnitTestCase
|
|||
*/
|
||||
public function filterIsAddedToQuery()
|
||||
{
|
||||
$this->configuration->expects($this->any())
|
||||
->method('get')
|
||||
->will($this->throwException(new InvalidArgumentException));
|
||||
$this->configureConfigurationMockWithDefault();
|
||||
|
||||
$searchRequest = new SearchRequest('SearchWord');
|
||||
$searchRequest->setFilter(['field' => 'content']);
|
||||
|
@ -95,9 +91,7 @@ class QueryFactoryTest extends AbstractUnitTestCase
|
|||
*/
|
||||
public function emptyFilterIsNotAddedToQuery()
|
||||
{
|
||||
$this->configuration->expects($this->any())
|
||||
->method('get')
|
||||
->will($this->throwException(new InvalidArgumentException));
|
||||
$this->configureConfigurationMockWithDefault();
|
||||
|
||||
$searchRequest = new SearchRequest('SearchWord');
|
||||
$searchRequest->setFilter([
|
||||
|
@ -122,12 +116,10 @@ class QueryFactoryTest extends AbstractUnitTestCase
|
|||
*/
|
||||
public function facetsAreAddedToQuery()
|
||||
{
|
||||
$this->configuration->expects($this->any())
|
||||
->method('get')
|
||||
->will($this->throwException(new InvalidArgumentException));
|
||||
$this->configureConfigurationMockWithDefault();
|
||||
$searchRequest = new SearchRequest('SearchWord');
|
||||
$searchRequest->addFacet(new FacetRequest('Identifier', 'FieldName'));
|
||||
$searchRequest->addFacet(new FacetRequest('Identifier 2', 'FieldName 2'));
|
||||
$searchRequest->addFacet(new FacetRequest('Identifier', ['terms' => ['field' => 'FieldName']]));
|
||||
$searchRequest->addFacet(new FacetRequest('Identifier 2', ['terms' => ['field' => 'FieldName 2']]));
|
||||
|
||||
$query = $this->subject->create($searchRequest);
|
||||
$this->assertSame(
|
||||
|
@ -153,9 +145,7 @@ class QueryFactoryTest extends AbstractUnitTestCase
|
|||
*/
|
||||
public function sizeIsAddedToQuery()
|
||||
{
|
||||
$this->configuration->expects($this->any())
|
||||
->method('get')
|
||||
->will($this->throwException(new InvalidArgumentException));
|
||||
$this->configureConfigurationMockWithDefault();
|
||||
$searchRequest = new SearchRequest('SearchWord');
|
||||
$searchRequest->setLimit(45);
|
||||
$searchRequest->setOffset(35);
|
||||
|
@ -179,9 +169,7 @@ class QueryFactoryTest extends AbstractUnitTestCase
|
|||
public function searchTermIsAddedToQuery()
|
||||
{
|
||||
$searchRequest = new SearchRequest('SearchWord');
|
||||
$this->configuration->expects($this->any())
|
||||
->method('get')
|
||||
->will($this->throwException(new InvalidArgumentException));
|
||||
$this->configureConfigurationMockWithDefault();
|
||||
$query = $this->subject->create($searchRequest);
|
||||
|
||||
$this->assertSame(
|
||||
|
@ -189,9 +177,11 @@ class QueryFactoryTest extends AbstractUnitTestCase
|
|||
'bool' => [
|
||||
'must' => [
|
||||
[
|
||||
'match' => [
|
||||
'_all' => [
|
||||
'query' => 'SearchWord',
|
||||
'multi_match' => [
|
||||
'type' => 'most_fields',
|
||||
'query' => 'SearchWord',
|
||||
'fields' => [
|
||||
'_all',
|
||||
],
|
||||
],
|
||||
],
|
||||
|
@ -219,9 +209,7 @@ class QueryFactoryTest extends AbstractUnitTestCase
|
|||
'50%',
|
||||
null
|
||||
));
|
||||
$this->configuration->expects($this->any())
|
||||
->method('get')
|
||||
->will($this->throwException(new InvalidArgumentException));
|
||||
$this->configureConfigurationMockWithDefault();
|
||||
$query = $this->subject->create($searchRequest);
|
||||
|
||||
$this->assertArraySubset(
|
||||
|
@ -229,10 +217,13 @@ class QueryFactoryTest extends AbstractUnitTestCase
|
|||
'bool' => [
|
||||
'must' => [
|
||||
[
|
||||
'match' => [
|
||||
'_all' => [
|
||||
'minimum_should_match' => '50%',
|
||||
'multi_match' => [
|
||||
'type' => 'most_fields',
|
||||
'query' => 'SearchWord',
|
||||
'fields' => [
|
||||
'_all',
|
||||
],
|
||||
'minimum_should_match' => '50%',
|
||||
],
|
||||
],
|
||||
],
|
||||
|
@ -253,12 +244,14 @@ class QueryFactoryTest extends AbstractUnitTestCase
|
|||
$this->configuration->expects($this->any())
|
||||
->method('get')
|
||||
->withConsecutive(
|
||||
['searching.fields.query'],
|
||||
['searching.boost'],
|
||||
['searching.fields.stored_fields'],
|
||||
['searching.fields.script_fields'],
|
||||
['searching.fieldValueFactor']
|
||||
)
|
||||
->will($this->onConsecutiveCalls(
|
||||
'_all',
|
||||
[
|
||||
'search_title' => 3,
|
||||
'search_abstract' => 1.5,
|
||||
|
@ -308,12 +301,14 @@ class QueryFactoryTest extends AbstractUnitTestCase
|
|||
$this->configuration->expects($this->any())
|
||||
->method('get')
|
||||
->withConsecutive(
|
||||
['searching.fields.query'],
|
||||
['searching.boost'],
|
||||
['searching.fields.stored_fields'],
|
||||
['searching.fields.script_fields'],
|
||||
['searching.fieldValueFactor']
|
||||
)
|
||||
->will($this->onConsecutiveCalls(
|
||||
'_all',
|
||||
$this->throwException(new InvalidArgumentException),
|
||||
$this->throwException(new InvalidArgumentException),
|
||||
$this->throwException(new InvalidArgumentException),
|
||||
|
@ -328,9 +323,11 @@ class QueryFactoryTest extends AbstractUnitTestCase
|
|||
'bool' => [
|
||||
'must' => [
|
||||
[
|
||||
'match' => [
|
||||
'_all' => [
|
||||
'query' => 'SearchWord',
|
||||
'multi_match' => [
|
||||
'type' => 'most_fields',
|
||||
'query' => 'SearchWord',
|
||||
'fields' => [
|
||||
'_all',
|
||||
],
|
||||
],
|
||||
],
|
||||
|
@ -352,9 +349,7 @@ class QueryFactoryTest extends AbstractUnitTestCase
|
|||
{
|
||||
$searchRequest = new SearchRequest();
|
||||
|
||||
$this->configuration->expects($this->any())
|
||||
->method('get')
|
||||
->will($this->throwException(new InvalidArgumentException));
|
||||
$this->configureConfigurationMockWithDefault();
|
||||
|
||||
$query = $this->subject->create($searchRequest);
|
||||
$this->assertInstanceOf(
|
||||
|
@ -364,6 +359,54 @@ class QueryFactoryTest extends AbstractUnitTestCase
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function configuredQueryFieldsAreAddedToQuery()
|
||||
{
|
||||
$searchRequest = new SearchRequest('SearchWord');
|
||||
|
||||
$this->configuration->expects($this->any())
|
||||
->method('get')
|
||||
->withConsecutive(
|
||||
['searching.fields.query'],
|
||||
['searching.boost'],
|
||||
['searching.fields.stored_fields'],
|
||||
['searching.fields.script_fields'],
|
||||
['searching.fieldValueFactor']
|
||||
)
|
||||
->will($this->onConsecutiveCalls(
|
||||
'_all, field1, field2',
|
||||
$this->throwException(new InvalidArgumentException),
|
||||
$this->throwException(new InvalidArgumentException),
|
||||
$this->throwException(new InvalidArgumentException),
|
||||
$this->throwException(new InvalidArgumentException)
|
||||
));
|
||||
|
||||
$query = $this->subject->create($searchRequest);
|
||||
$this->assertArraySubset(
|
||||
[
|
||||
'bool' => [
|
||||
'must' => [
|
||||
[
|
||||
'multi_match' => [
|
||||
'type' => 'most_fields',
|
||||
'query' => 'SearchWord',
|
||||
'fields' => [
|
||||
'_all',
|
||||
'field1',
|
||||
'field2',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
$query->toArray()['query'],
|
||||
'Configured fields were not added to query as configured.'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
|
@ -433,12 +476,14 @@ class QueryFactoryTest extends AbstractUnitTestCase
|
|||
$this->configuration->expects($this->any())
|
||||
->method('get')
|
||||
->withConsecutive(
|
||||
['searching.fields.query'],
|
||||
['searching.boost'],
|
||||
['searching.fields.stored_fields'],
|
||||
['searching.fields.script_fields'],
|
||||
['searching.fieldValueFactor']
|
||||
)
|
||||
->will($this->onConsecutiveCalls(
|
||||
'_all',
|
||||
$this->throwException(new InvalidArgumentException),
|
||||
$this->throwException(new InvalidArgumentException),
|
||||
[
|
||||
|
@ -521,9 +566,7 @@ class QueryFactoryTest extends AbstractUnitTestCase
|
|||
]
|
||||
));
|
||||
|
||||
$this->configuration->expects($this->any())
|
||||
->method('get')
|
||||
->will($this->throwException(new InvalidArgumentException));
|
||||
$this->configureConfigurationMockWithDefault();
|
||||
|
||||
$query = $this->subject->create($searchRequest);
|
||||
$this->assertSame(
|
||||
|
@ -558,9 +601,7 @@ class QueryFactoryTest extends AbstractUnitTestCase
|
|||
null
|
||||
));
|
||||
|
||||
$this->configuration->expects($this->any())
|
||||
->method('get')
|
||||
->will($this->throwException(new InvalidArgumentException));
|
||||
$this->configureConfigurationMockWithDefault();
|
||||
|
||||
$query = $this->subject->create($searchRequest);
|
||||
$this->assertTrue(
|
||||
|
@ -568,4 +609,17 @@ class QueryFactoryTest extends AbstractUnitTestCase
|
|||
'Sort was added to query even if not configured.'
|
||||
);
|
||||
}
|
||||
|
||||
protected function configureConfigurationMockWithDefault()
|
||||
{
|
||||
$this->configuration->expects($this->any())
|
||||
->method('get')
|
||||
->will($this->returnCallback(function ($configName) {
|
||||
if ($configName === 'searching.fields.query') {
|
||||
return '_all';
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException();
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -83,19 +83,14 @@ class DataHandlerFinisherTest extends AbstractUnitTestCase
|
|||
public function possibleFinisherSetup() : array
|
||||
{
|
||||
return [
|
||||
'valid add configuration' => [
|
||||
'action' => 'add',
|
||||
'nonCalledActions' => ['delete', 'update'],
|
||||
'expectedSecondArgument' => ['uid' => 23],
|
||||
],
|
||||
'valid update configuration' => [
|
||||
'action' => 'update',
|
||||
'nonCalledActions' => ['delete', 'add'],
|
||||
'nonCalledActions' => ['delete'],
|
||||
'expectedSecondArgument' => ['uid' => 23],
|
||||
],
|
||||
'valid delete configuration' => [
|
||||
'action' => 'delete',
|
||||
'nonCalledActions' => ['update', 'add'],
|
||||
'nonCalledActions' => ['update'],
|
||||
'expectedSecondArgument' => 23,
|
||||
],
|
||||
];
|
||||
|
@ -109,7 +104,7 @@ class DataHandlerFinisherTest extends AbstractUnitTestCase
|
|||
{
|
||||
$this->subject->setOptions($options);
|
||||
|
||||
foreach (['add', 'update', 'delete'] as $nonCalledAction) {
|
||||
foreach (['update', 'delete'] as $nonCalledAction) {
|
||||
$this->dataHandlerMock->expects($this->never())->method($nonCalledAction);
|
||||
}
|
||||
|
||||
|
|
|
@ -15,8 +15,8 @@
|
|||
"TYPO3\\CMS\\Core\\Tests\\": ".Build/vendor/typo3/cms/typo3/sysext/core/Tests/"
|
||||
}
|
||||
},
|
||||
"require" : {
|
||||
"php": ">=7.1.0",
|
||||
"require": {
|
||||
"php": ">=7.0.0",
|
||||
"typo3/cms": "~8.7",
|
||||
"ruflin/elastica": "~3.2"
|
||||
},
|
||||
|
|
4
ext_conf_template.txt
Normal file
4
ext_conf_template.txt
Normal file
|
@ -0,0 +1,4 @@
|
|||
disable {
|
||||
# cat=basic/enable; type=boolean; label=Disable Elasticsearch, which is enabled by default
|
||||
elasticsearch = true
|
||||
}
|
|
@ -37,11 +37,18 @@ call_user_func(
|
|||
]
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\CMS\Extbase\Object\Container\Container')
|
||||
->registerImplementation(
|
||||
'Codappix\SearchCore\Connection\ConnectionInterface',
|
||||
'Codappix\SearchCore\Connection\Elasticsearch'
|
||||
);
|
||||
// API does make use of object manager, therefore use GLOBALS
|
||||
$extensionConfiguration = unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf'][$extensionKey]);
|
||||
if ($extensionConfiguration === false
|
||||
|| !isset($extensionConfiguration['disable.']['elasticsearch'])
|
||||
|| $extensionConfiguration['disable.']['elasticsearch'] !== '1'
|
||||
) {
|
||||
\TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\Object\Container\Container::class)
|
||||
->registerImplementation(
|
||||
\Codappix\SearchCore\Connection\ConnectionInterface::class,
|
||||
\Codappix\SearchCore\Connection\Elasticsearch::class
|
||||
);
|
||||
}
|
||||
},
|
||||
$_EXTKEY
|
||||
);
|
||||
|
|
Loading…
Reference in a new issue