From 5dd0759bb603c590b0a6031c1a12e3cb4a1ea583 Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Tue, 6 Jun 2017 12:11:28 +0200 Subject: [PATCH 01/20] TASK: Fix file permissions --- Configuration/TypoScript/constants.txt | 0 Configuration/TypoScript/setup.txt | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 Configuration/TypoScript/constants.txt mode change 100755 => 100644 Configuration/TypoScript/setup.txt diff --git a/Configuration/TypoScript/constants.txt b/Configuration/TypoScript/constants.txt old mode 100755 new mode 100644 diff --git a/Configuration/TypoScript/setup.txt b/Configuration/TypoScript/setup.txt old mode 100755 new mode 100644 From 3a2523e1d2e8e61350150a29c0f4ce5e098d2ee4 Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Tue, 6 Jun 2017 12:32:27 +0200 Subject: [PATCH 02/20] WIP|FEATURE: First basic implementation of filter * Working version without further architecture. * Manually tested. * Still need to move to new architecture and cover with tests. --- Classes/Connection/Elasticsearch.php | 27 ++++++++++++++++++++-- Classes/Domain/Model/SearchRequest.php | 31 +++++++++++++++++++++++++- 2 files changed, 55 insertions(+), 3 deletions(-) diff --git a/Classes/Connection/Elasticsearch.php b/Classes/Connection/Elasticsearch.php index 560ca07..7f963ea 100644 --- a/Classes/Connection/Elasticsearch.php +++ b/Classes/Connection/Elasticsearch.php @@ -146,12 +146,35 @@ class Elasticsearch implements Singleton, ConnectionInterface { $this->logger->debug('Search for', [$searchRequest->getSearchTerm()]); + $query = [ + 'bool' => [ + 'must' => [ + [ + 'match' => [ + '_all' => $searchRequest->getSearchTerm() + ], + ], + ], + ], + ]; + + if ($searchRequest->hasFilter()) { + $queryFilter = []; + foreach ($searchRequest->getFilter() as $field => $value) { + $queryFilter[$field] = $value; + } + + $query['bool']['filter'] = [ + 'term' => $queryFilter, + ]; + } + $search = new \Elastica\Search($this->connection->getClient()); $search->addIndex('typo3content'); - + $search->setQuery(new \Elastica\Query(['query' => $query])); // TODO: Return wrapped result to implement our interface. // Also update php doc to reflect the change. - return $search->search('"' . $searchRequest->getSearchTerm() . '"'); + return $search->search(); } /** diff --git a/Classes/Domain/Model/SearchRequest.php b/Classes/Domain/Model/SearchRequest.php index 1de2f71..105cc45 100644 --- a/Classes/Domain/Model/SearchRequest.php +++ b/Classes/Domain/Model/SearchRequest.php @@ -32,7 +32,12 @@ class SearchRequest implements SearchRequestInterface * * @var string */ - protected $query; + protected $query = ''; + + /** + * @var array + */ + protected $filter = []; /** * @param string $query @@ -57,4 +62,28 @@ class SearchRequest implements SearchRequestInterface { return $this->query; } + + /** + * @param array $filter + */ + public function setFilter(array $filter) + { + $this->filter = $filter; + } + + /** + * @return bool + */ + public function hasFilter() + { + return count($this->filter); + } + + /** + * @return array + */ + public function getFilter() + { + return $this->filter; + } } From 1a41c5e237729026696034d04a67bcfca7384a71 Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Tue, 6 Jun 2017 13:53:08 +0200 Subject: [PATCH 03/20] FEATURE: Add filter to search * Allow to filter results by field values. --- .travis.yml | 4 +- Classes/Connection/Elasticsearch.php | 37 ++++------ Classes/Connection/SearchRequestInterface.php | 10 +++ Classes/Domain/Search/QueryFactory.php | 72 +++++++++++++++++++ Makefile | 5 ++ .../AbstractFunctionalTestCase.php | 7 ++ .../Connection/Elasticsearch/FilterTest.php | 61 ++++++++++++++++ .../Functional/Fixtures/Searching/Filter.xml | 42 +++++++++++ Tests/Unit/AbstractUnitTestCase.php | 27 +++++++ Tests/Unit/Domain/Search/QueryFactoryTest.php | 56 +++++++++++++++ Tests/Unit/UnitTests.xml | 28 ++++++++ 11 files changed, 323 insertions(+), 26 deletions(-) create mode 100644 Classes/Domain/Search/QueryFactory.php create mode 100644 Tests/Functional/Connection/Elasticsearch/FilterTest.php create mode 100644 Tests/Functional/Fixtures/Searching/Filter.xml create mode 100644 Tests/Unit/AbstractUnitTestCase.php create mode 100644 Tests/Unit/Domain/Search/QueryFactoryTest.php create mode 100644 Tests/Unit/UnitTests.xml diff --git a/.travis.yml b/.travis.yml index e583e51..123363a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -53,7 +53,9 @@ services: install: make install -script: make functionalTests +script: + - make unitTests + - make functionalTests after_script: - make uploadCodeCoverage diff --git a/Classes/Connection/Elasticsearch.php b/Classes/Connection/Elasticsearch.php index 7f963ea..386e19c 100644 --- a/Classes/Connection/Elasticsearch.php +++ b/Classes/Connection/Elasticsearch.php @@ -21,6 +21,7 @@ namespace Leonmrni\SearchCore\Connection; */ use TYPO3\CMS\Core\SingletonInterface as Singleton; +use Leonmrni\SearchCore\Domain\Search\QueryFactory; /** * Outer wrapper to elasticsearch. @@ -47,6 +48,11 @@ class Elasticsearch implements Singleton, ConnectionInterface */ protected $documentFactory; + /** + * @var QueryFactory + */ + protected $queryFactory; + /** * @var \TYPO3\CMS\Core\Log\Logger */ @@ -67,17 +73,20 @@ class Elasticsearch implements Singleton, ConnectionInterface * @param Elasticsearch\IndexFactory $indexFactory * @param Elasticsearch\TypeFactory $typeFactory * @param Elasticsearch\DocumentFactory $documentFactory + * @param QueryFactory $queryFactory */ public function __construct( Elasticsearch\Connection $connection, Elasticsearch\IndexFactory $indexFactory, Elasticsearch\TypeFactory $typeFactory, - Elasticsearch\DocumentFactory $documentFactory + Elasticsearch\DocumentFactory $documentFactory, + QueryFactory $queryFactory ) { $this->connection = $connection; $this->indexFactory = $indexFactory; $this->typeFactory = $typeFactory; $this->documentFactory = $documentFactory; + $this->queryFactory = $queryFactory; } public function addDocument($documentType, array $document) @@ -146,32 +155,10 @@ class Elasticsearch implements Singleton, ConnectionInterface { $this->logger->debug('Search for', [$searchRequest->getSearchTerm()]); - $query = [ - 'bool' => [ - 'must' => [ - [ - 'match' => [ - '_all' => $searchRequest->getSearchTerm() - ], - ], - ], - ], - ]; - - if ($searchRequest->hasFilter()) { - $queryFilter = []; - foreach ($searchRequest->getFilter() as $field => $value) { - $queryFilter[$field] = $value; - } - - $query['bool']['filter'] = [ - 'term' => $queryFilter, - ]; - } - $search = new \Elastica\Search($this->connection->getClient()); $search->addIndex('typo3content'); - $search->setQuery(new \Elastica\Query(['query' => $query])); + $search->setQuery($this->queryFactory->create($this, $searchRequest)); + // TODO: Return wrapped result to implement our interface. // Also update php doc to reflect the change. return $search->search(); diff --git a/Classes/Connection/SearchRequestInterface.php b/Classes/Connection/SearchRequestInterface.php index ecf7a74..603c02f 100644 --- a/Classes/Connection/SearchRequestInterface.php +++ b/Classes/Connection/SearchRequestInterface.php @@ -31,4 +31,14 @@ interface SearchRequestInterface * @return string */ public function getSearchTerm(); + + /** + * @return bool + */ + public function hasFilter(); + + /** + * @return array + */ + public function getFilter(); } diff --git a/Classes/Domain/Search/QueryFactory.php b/Classes/Domain/Search/QueryFactory.php new file mode 100644 index 0000000..2f3ac25 --- /dev/null +++ b/Classes/Domain/Search/QueryFactory.php @@ -0,0 +1,72 @@ + + * + * 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 Leonmrni\SearchCore\Connection\ConnectionInterface; +use Leonmrni\SearchCore\Connection\Elasticsearch\Query; +use Leonmrni\SearchCore\Connection\SearchRequestInterface; + +class QueryFactory +{ + /** + * @param ConnectionInterface $connection + * @param SearchRequestInterface $searchRequest + * + * @return \Elastica\Query + */ + public function create( + ConnectionInterface $connection, + SearchRequestInterface $searchRequest + ) { + return $this->createElasticaQuery($searchRequest); + } + + /** + * @param SearchRequestInterface $searchRequest + * @return \Elastica\Query + */ + protected function createElasticaQuery(SearchRequestInterface $searchRequest) + { + $query = [ + 'bool' => [ + 'must' => [ + [ + 'match' => [ + '_all' => $searchRequest->getSearchTerm() + ], + ], + ], + ], + ]; + $queryFilter = []; + + if ($searchRequest->hasFilter()) { + foreach ($searchRequest->getFilter() as $field => $value) { + $queryFilter[$field] = $value; + } + $query['bool']['filter'] = [ + 'term' => $queryFilter, + ]; + } + + return new \Elastica\Query(['query' => $query]); + } +} diff --git a/Makefile b/Makefile index 2520ab0..6d058c0 100644 --- a/Makefile +++ b/Makefile @@ -23,6 +23,11 @@ functionalTests: .Build/bin/phpunit --colors --debug -v \ -c Tests/Functional/FunctionalTests.xml +unitTests: + TYPO3_PATH_WEB=$(TYPO3_WEB_DIR) \ + .Build/bin/phpunit --colors --debug -v \ + -c Tests/Unit/UnitTests.xml + uploadCodeCoverage: uploadCodeCoverageToScrutinizer uploadCodeCoverageToCodacy uploadCodeCoverageToScrutinizer: diff --git a/Tests/Functional/Connection/Elasticsearch/AbstractFunctionalTestCase.php b/Tests/Functional/Connection/Elasticsearch/AbstractFunctionalTestCase.php index cdd8ddf..363ad6d 100644 --- a/Tests/Functional/Connection/Elasticsearch/AbstractFunctionalTestCase.php +++ b/Tests/Functional/Connection/Elasticsearch/AbstractFunctionalTestCase.php @@ -43,11 +43,18 @@ abstract class AbstractFunctionalTestCase extends BaseFunctionalTestCase 'host' => getenv('ES_HOST') ?: \Elastica\Connection::DEFAULT_HOST, 'port' => getenv('ES_PORT') ?: \Elastica\Connection::DEFAULT_PORT, ]); + + $this->cleanUp(); } public function tearDown() { // Delete everything so next test starts clean. + $this->cleanUp(); + } + + protected function cleanUp() + { $this->client->getIndex('_all')->delete(); $this->client->getIndex('_all')->clearCache(); } diff --git a/Tests/Functional/Connection/Elasticsearch/FilterTest.php b/Tests/Functional/Connection/Elasticsearch/FilterTest.php new file mode 100644 index 0000000..88ae37f --- /dev/null +++ b/Tests/Functional/Connection/Elasticsearch/FilterTest.php @@ -0,0 +1,61 @@ + + * + * 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 Leonmrni\SearchCore\Domain\Index\IndexerFactory; +use Leonmrni\SearchCore\Domain\Model\SearchRequest; +use Leonmrni\SearchCore\Domain\Search\SearchService; +use TYPO3\CMS\Extbase\Object\ObjectManager; + +class FilterTest extends AbstractFunctionalTestCase +{ + protected function getDataSets() + { + return array_merge( + parent::getDataSets(), + ['Tests/Functional/Fixtures/Searching/Filter.xml'] + ); + } + + /** + * @test + */ + public function itsPossibleToFilterResultsByASingleField() + { + \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(2, count($result), 'Did not receive both indexed elements without filter.'); + + $searchRequest->setFilter(['CType' => 'html']); + $result = $searchService->search($searchRequest); + $this->assertSame('5', $result[0]->getData()['uid'], 'Did not get the expected result entry.'); + $this->assertSame(1, count($result), 'Did not receive the single filtered element.'); + } +} diff --git a/Tests/Functional/Fixtures/Searching/Filter.xml b/Tests/Functional/Fixtures/Searching/Filter.xml new file mode 100644 index 0000000..103a4da --- /dev/null +++ b/Tests/Functional/Fixtures/Searching/Filter.xml @@ -0,0 +1,42 @@ + + + + 5 + 1 + 1480686370 + 1480686370 + 0 + 72 + html +
indexed content element with html ctype
+ Search Word + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +
+ + + 6 + 1 + 1480686370 + 1480686370 + 0 + 72 + header +
indexed content element with header ctype
+ Search Word + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +
+
diff --git a/Tests/Unit/AbstractUnitTestCase.php b/Tests/Unit/AbstractUnitTestCase.php new file mode 100644 index 0000000..f3281c1 --- /dev/null +++ b/Tests/Unit/AbstractUnitTestCase.php @@ -0,0 +1,27 @@ + + * + * 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\Core\Tests\UnitTestCase as CoreTestCase; + +abstract class AbstractUnitTestCase extends CoreTestCase +{ +} diff --git a/Tests/Unit/Domain/Search/QueryFactoryTest.php b/Tests/Unit/Domain/Search/QueryFactoryTest.php new file mode 100644 index 0000000..7fc6b15 --- /dev/null +++ b/Tests/Unit/Domain/Search/QueryFactoryTest.php @@ -0,0 +1,56 @@ + + * + * 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 Leonmrni\SearchCore\Connection; +use Leonmrni\SearchCore\Domain\Model\SearchRequest; +use Leonmrni\SearchCore\Domain\Search\QueryFactory; +use Leonmrni\SearchCore\Tests\Unit\AbstractUnitTestCase; + +class QueryFactoryTest extends AbstractUnitTestCase +{ + protected $subject; + + public function setUp() + { + parent::setUp(); + + $this->subject = new QueryFactory; + } + + /** + * @test + */ + public function creatonOfQueryWorksInGeneral() + { + $connection = $this->getMockBuilder(Connection\Elasticsearch::class) + ->disableOriginalConstructor() + ->getMock(); + $searchRequest = new SearchRequest('SearchWord'); + + $query = $this->subject->create($connection, $searchRequest); + $this->assertInstanceOf( + \Elastica\Query::class, + $query, + 'Factory did not create the expected instance.' + ); + } +} diff --git a/Tests/Unit/UnitTests.xml b/Tests/Unit/UnitTests.xml new file mode 100644 index 0000000..6456405 --- /dev/null +++ b/Tests/Unit/UnitTests.xml @@ -0,0 +1,28 @@ + + + + + . + + + + + + ../../Classes + + + From bb9e29574f84e16a81e2888a78fb60e41f63b8a4 Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Tue, 6 Jun 2017 14:25:03 +0200 Subject: [PATCH 04/20] TASK: Use elasticsearch 5.2 on travis * As we make use of newer features that are incompatible with travis own elasticsearch version 1.x. --- .travis.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 123363a..03a193c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,12 @@ +sudo: true + +addons: + apt: + packages: + - oracle-java8-set-default +before_install: + - curl -O https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-5.2.0.deb && sudo dpkg -i --force-confnew elasticsearch-5.2.0.deb && sudo service elasticsearch start + language: php php: @@ -49,7 +58,6 @@ matrix: services: - mysql - - elasticsearch install: make install From f5729c276325e8d8696eb8a51bd0cc80b1f60bc5 Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Tue, 6 Jun 2017 15:33:06 +0200 Subject: [PATCH 05/20] BUGFIX: Keep return type * Return boolean type. --- Classes/Domain/Model/SearchRequest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Classes/Domain/Model/SearchRequest.php b/Classes/Domain/Model/SearchRequest.php index 105cc45..b88c866 100644 --- a/Classes/Domain/Model/SearchRequest.php +++ b/Classes/Domain/Model/SearchRequest.php @@ -76,7 +76,7 @@ class SearchRequest implements SearchRequestInterface */ public function hasFilter() { - return count($this->filter); + return count($this->filter) > 0; } /** From f4a9531fe59df1e40b6090342121e3b6664fee59 Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Tue, 6 Jun 2017 16:25:35 +0200 Subject: [PATCH 06/20] TASK: Remove unnecessary code * As filter is already in the format we need, we can just use it instead of using a foreach. --- Classes/Domain/Search/QueryFactory.php | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/Classes/Domain/Search/QueryFactory.php b/Classes/Domain/Search/QueryFactory.php index 2f3ac25..31c50df 100644 --- a/Classes/Domain/Search/QueryFactory.php +++ b/Classes/Domain/Search/QueryFactory.php @@ -56,15 +56,9 @@ class QueryFactory ], ], ]; - $queryFilter = []; if ($searchRequest->hasFilter()) { - foreach ($searchRequest->getFilter() as $field => $value) { - $queryFilter[$field] = $value; - } - $query['bool']['filter'] = [ - 'term' => $queryFilter, - ]; + $query['bool']['filter'] = ['term' => $searchRequest->getFilter()]; } return new \Elastica\Query(['query' => $query]); From f453592b39158e41a2f46121253e0755de1b618c Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Thu, 8 Jun 2017 08:38:14 +0200 Subject: [PATCH 07/20] TASK: Add further tests and cast search input * Map user input to string in any case. * Add tests to check whether filter is added to query. * Add test to check whether input is casted to string. --- Classes/Domain/Model/SearchRequest.php | 4 +- Tests/Unit/Domain/Search/QueryFactoryTest.php | 43 +++++++++++++++++++ 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/Classes/Domain/Model/SearchRequest.php b/Classes/Domain/Model/SearchRequest.php index b88c866..f1ad18e 100644 --- a/Classes/Domain/Model/SearchRequest.php +++ b/Classes/Domain/Model/SearchRequest.php @@ -44,7 +44,7 @@ class SearchRequest implements SearchRequestInterface */ public function __construct($query) { - $this->query = $query; + $this->query = (string) $query; } /** @@ -68,7 +68,7 @@ class SearchRequest implements SearchRequestInterface */ public function setFilter(array $filter) { - $this->filter = $filter; + $this->filter = array_map('strval', $filter); } /** diff --git a/Tests/Unit/Domain/Search/QueryFactoryTest.php b/Tests/Unit/Domain/Search/QueryFactoryTest.php index 7fc6b15..83f031e 100644 --- a/Tests/Unit/Domain/Search/QueryFactoryTest.php +++ b/Tests/Unit/Domain/Search/QueryFactoryTest.php @@ -53,4 +53,47 @@ class QueryFactoryTest extends AbstractUnitTestCase 'Factory did not create the expected instance.' ); } + + /** + * @test + */ + public function filterIsAddedToQuery() + { + $connection = $this->getMockBuilder(Connection\Elasticsearch::class) + ->disableOriginalConstructor() + ->getMock(); + $searchRequest = new SearchRequest('SearchWord'); + $searchRequest->setFilter(['field' => 'content']); + + $query = $this->subject->create($connection, $searchRequest); + $this->assertSame( + ['field' => 'content'], + $query->toArray()['query']['bool']['filter']['term'], + 'Filter was not added to query.' + ); + } + + /** + * @test + */ + public function userInputIsAlwaysString() + { + $connection = $this->getMockBuilder(Connection\Elasticsearch::class) + ->disableOriginalConstructor() + ->getMock(); + $searchRequest = new SearchRequest(10); + $searchRequest->setFilter(['field' => 20]); + + $query = $this->subject->create($connection, $searchRequest); + $this->assertSame( + '10', + $query->toArray()['query']['bool']['must'][0]['match']['_all'], + 'Search word was not escaped as expected.' + ); + $this->assertSame( + '20', + $query->toArray()['query']['bool']['filter']['term']['field'], + 'Search word was not escaped as expected.' + ); + } } From 3553c443e2e06da2cdc44aed4477c7470579a23f Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Tue, 27 Jun 2017 16:51:33 +0200 Subject: [PATCH 08/20] FEATURE: Adjust configuration structure * To support further configuration, specific to identifiers / tables. * E.g. mapping and boost configuration should be possible. * Adjust docs and settings. * Adjust tests and code. --- Classes/Command/IndexCommandController.php | 3 ++ .../Index/TcaIndexer/TcaTableService.php | 7 +++-- Classes/Domain/Service/DataHandler.php | 13 ++++++++- Configuration/TypoScript/constants.txt | 24 +++++++-------- Configuration/TypoScript/setup.txt | 11 +++---- Documentation/source/concepts.rst | 2 +- Documentation/source/configuration.rst | 29 +++++-------------- Tests/Functional/Fixtures/BasicSetup.ts | 6 ++-- .../TcaIndexer/RespectRootLineBlacklist.ts | 4 +-- .../Fixtures/Indexing/UserWhereClause.ts | 8 ++--- 10 files changed, 49 insertions(+), 58 deletions(-) diff --git a/Classes/Command/IndexCommandController.php b/Classes/Command/IndexCommandController.php index c1ade27..55ac4df 100644 --- a/Classes/Command/IndexCommandController.php +++ b/Classes/Command/IndexCommandController.php @@ -57,6 +57,9 @@ class IndexCommandController extends CommandController { // TODO: Allow to index multiple tables at once? // TODO: Also allow to index everything? + + // TODO: There is no test yet! + // TODO: Add test, adjust config path if (! in_array($table, GeneralUtility::trimExplode(',', $this->configuration->get('indexer.tca.allowedTables')))) { $this->outputLine('Table is not allowed for indexing.'); $this->quit(1); diff --git a/Classes/Domain/Index/TcaIndexer/TcaTableService.php b/Classes/Domain/Index/TcaIndexer/TcaTableService.php index 936d425..7d69e5b 100644 --- a/Classes/Domain/Index/TcaIndexer/TcaTableService.php +++ b/Classes/Domain/Index/TcaIndexer/TcaTableService.php @@ -151,7 +151,8 @@ class TcaTableService . ' AND pages.no_search = 0' ; - $userDefinedWhere = $this->configuration->getIfExists('indexer.tca.' . $this->tableName . '.additionalWhereClause'); + // TODO: There is no test covering this option yet? + $userDefinedWhere = $this->configuration->getIfExists('indexing.' . $this->getTableName() . '.additionalWhereClause'); if (is_string($userDefinedWhere)) { $whereClause .= ' AND ' . $userDefinedWhere; } @@ -269,7 +270,7 @@ class TcaTableService */ protected function isBlackListedRootLineConfigured() { - return (bool) $this->configuration->getIfExists('indexer.tca.rootLineBlacklist'); + return (bool) $this->configuration->getIfExists('indexing.' . $this->getTableName() . '.rootLineBlacklist'); } /** @@ -279,6 +280,6 @@ class TcaTableService */ protected function getBlackListedRootLine() { - return GeneralUtility::intExplode(',', $this->configuration->getIfExists('indexer.tca.rootLineBlacklist')); + return GeneralUtility::intExplode(',', $this->configuration->getIfExists('indexing.' . $this->getTableName() . '.rootLineBlacklist')); } } diff --git a/Classes/Domain/Service/DataHandler.php b/Classes/Domain/Service/DataHandler.php index 213b9cc..578589a 100644 --- a/Classes/Domain/Service/DataHandler.php +++ b/Classes/Domain/Service/DataHandler.php @@ -21,6 +21,7 @@ namespace Leonmrni\SearchCore\Domain\Service; */ use Leonmrni\SearchCore\Configuration\ConfigurationContainerInterface; +use Leonmrni\SearchCore\Domain\Index\TcaIndexer; use TYPO3\CMS\Core\SingletonInterface as Singleton; use TYPO3\CMS\Core\Utility\GeneralUtility; @@ -86,7 +87,17 @@ class DataHandler implements Singleton */ public function getAllowedTablesForIndexing() { - return GeneralUtility::trimExplode(',', $this->configuration->get('indexer.tca.allowedTables')); + $tables = []; + foreach ($this->configuration->get('indexing') as $tableName => $indexConfiguration) { + if ($indexConfiguration['indexer'] === TcaIndexer::class) { + $tables[] = $tableName; + continue; + } + // TODO: Support custom indexer. + // Define "interface" / option which is used. + } + + return $tables; } /** diff --git a/Configuration/TypoScript/constants.txt b/Configuration/TypoScript/constants.txt index 50f57c3..f97c039 100755 --- a/Configuration/TypoScript/constants.txt +++ b/Configuration/TypoScript/constants.txt @@ -8,20 +8,16 @@ plugin { } } - indexer { - tca { - # Pages are not supported yet, see - # https://github.com/DanielSiepmann/search_core/issues/24 but - # should also be added, together with additionalWhereClause - # based on doktypes - allowedTables = tt_content - - tt_content { - additionalWhereClause ( - pages.doktype NOT IN (3, 199) - AND tt_content.CType NOT IN ('gridelements_pi1', 'list', 'div', 'menu', 'shortcut', 'search', 'login') - ) - } + indexing { + # Pages are not supported yet, see + # https://github.com/DanielSiepmann/search_core/issues/24 but + # should also be added, together with additionalWhereClause + # based on doktypes + tt_content { + additionalWhereClause ( + pages.doktype NOT IN (3, 199) + AND tt_content.CType NOT IN ('gridelements_pi1', 'list', 'div', 'menu', 'shortcut', 'search', 'login') + ) } } } diff --git a/Configuration/TypoScript/setup.txt b/Configuration/TypoScript/setup.txt index afa15be..2d58b35 100755 --- a/Configuration/TypoScript/setup.txt +++ b/Configuration/TypoScript/setup.txt @@ -8,13 +8,10 @@ plugin { } } - indexer { - tca { - allowedTables = {$plugin.tx_searchcore.settings.indexer.tca.allowedTables} - - tt_content { - additionalWhereClause = {$plugin.tx_searchcore.settings.indexer.tca.tt_content.additionalWhereClause} - } + indexing { + tt_content { + indexer = Leonmrni\SearchCore\Domain\Index\TcaIndexer + additionalWhereClause = {$plugin.tx_searchcore.settings.indexing.tt_content.additionalWhereClause} } } } diff --git a/Documentation/source/concepts.rst b/Documentation/source/concepts.rst index 4d48d35..fc0569a 100644 --- a/Documentation/source/concepts.rst +++ b/Documentation/source/concepts.rst @@ -25,6 +25,6 @@ Indexing -------- The indexing is done by one of the available indexer. It should be possible to define the indexer to -use for certein document types. Also it should be possible to write custom indexer to use. +use for certain document types. Also it should be possible to write custom indexer to use. Currently only the :ref:`TcaIndexer` is provided. diff --git a/Documentation/source/configuration.rst b/Documentation/source/configuration.rst index fb51d11..1f16e06 100644 --- a/Documentation/source/configuration.rst +++ b/Documentation/source/configuration.rst @@ -38,7 +38,7 @@ Options The following section contains the different options, e.g. for :ref:`connections` and :ref:`indexer`: ``plugin.tx_searchcore.settings.connection`` or -``plugin.tx_searchcore.settings.index``. +``plugin.tx_searchcore.settings.indexing``. .. _configuration_options_connection: @@ -106,8 +106,9 @@ Configured as:: plugin { tx_searchcore { settings { - indexer { - indexerName { + indexing { + identifier { + indexer = Fully Qualified Classname // the settings } } @@ -115,26 +116,10 @@ Configured as:: } } -Where ``indexerName`` is one of the available :ref:`indexer`. +Where ``identifier`` is up to you, but should match table names to make :ref:`TcaIndexer` work. The following settings are available. For each setting its documented which indexer consumes it. -.. _allowedTables: - -``allowedTables`` -""""""""""""""""" - - Used by: :ref:`TcaIndexer`. - - Defines which TYPO3 tables are allowed to be indexed. Only white listed tables will be processed - through Command Line Interface and Hooks. - - Contains a comma separated list of table names. Spaces are trimmed. - - Example:: - - plugin.tx_searchcore.settings.indexer.tca.allowedTables = tt_content, fe_users - .. _rootLineBlacklist: ``rootLineBlacklist`` @@ -151,7 +136,7 @@ The following settings are available. For each setting its documented which inde Example:: - plugin.tx_searchcore.settings.index.tca.rootLineBlacklist = 3, 10, 100 + plugin.tx_searchcore.settings.indexing..rootLineBlacklist = 3, 10, 100 Also it's possible to define some behaviour for the different document types. In context of TYPO3 tables are used as document types 1:1. It's possible to configure different tables. The following @@ -170,7 +155,7 @@ options are available: Example:: - plugin.tx_searchcore.settings.index.tca.tt_content.additionalWhereClause = tt_content.CType NOT IN ('gridelements_pi1', 'list', 'div', 'menu') + plugin.tx_searchcore.settings.indexing..additionalWhereClause = tt_content.CType NOT IN ('gridelements_pi1', 'list', 'div', 'menu') .. attention:: diff --git a/Tests/Functional/Fixtures/BasicSetup.ts b/Tests/Functional/Fixtures/BasicSetup.ts index 510e2a1..72163e3 100644 --- a/Tests/Functional/Fixtures/BasicSetup.ts +++ b/Tests/Functional/Fixtures/BasicSetup.ts @@ -8,9 +8,9 @@ plugin { } } - indexer { - tca { - allowedTables = tt_content + indexing { + tt_content { + indexer = Leonmrni\SearchCore\Domain\Index\TcaIndexer } } } diff --git a/Tests/Functional/Fixtures/Indexing/TcaIndexer/RespectRootLineBlacklist.ts b/Tests/Functional/Fixtures/Indexing/TcaIndexer/RespectRootLineBlacklist.ts index 44013e7..c0c1cd6 100644 --- a/Tests/Functional/Fixtures/Indexing/TcaIndexer/RespectRootLineBlacklist.ts +++ b/Tests/Functional/Fixtures/Indexing/TcaIndexer/RespectRootLineBlacklist.ts @@ -1,8 +1,8 @@ plugin { tx_searchcore { settings { - indexer { - tca { + indexing { + tt_content { rootLineBlacklist = 3 } } diff --git a/Tests/Functional/Fixtures/Indexing/UserWhereClause.ts b/Tests/Functional/Fixtures/Indexing/UserWhereClause.ts index d79bb14..7478ef1 100644 --- a/Tests/Functional/Fixtures/Indexing/UserWhereClause.ts +++ b/Tests/Functional/Fixtures/Indexing/UserWhereClause.ts @@ -1,11 +1,9 @@ plugin { tx_searchcore { settings { - indexer { - tca { - tt_content { - additionalWhereClause = tt_content.CType NOT IN ('div') - } + indexing { + tt_content { + additionalWhereClause = tt_content.CType NOT IN ('div') } } } From dfed17bb6c51c1c49164386e896663c75412ca0b Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Thu, 29 Jun 2017 08:42:38 +0200 Subject: [PATCH 09/20] TASK: Update docs * Cover new features and how to use them. --- Documentation/source/features.rst | 41 +++++++++++++++++++++++++++++++ Documentation/source/index.rst | 1 + Documentation/source/usage.rst | 27 ++++++++++++++++++++ 3 files changed, 69 insertions(+) create mode 100644 Documentation/source/features.rst diff --git a/Documentation/source/features.rst b/Documentation/source/features.rst new file mode 100644 index 0000000..c715512 --- /dev/null +++ b/Documentation/source/features.rst @@ -0,0 +1,41 @@ +.. _features: + +Features +======== + +The following features are currently provided: + +.. _features_indexing: + +Indexing +-------- + +Indexing data to Elasticsearch is provided. The extension delivers an indexer for TCA with zero +configuration needs. Still it's possible to configure the indexer. + +Own indexer are not possible yet, but will. + +.. _features_search: + +Searching +--------- + +Currently all fields are searched for a single search input. + +Also multiple filter are supported. Filtering results by fields for string contents. + +.. _features_planned: + +Planned +--------- + +The following features are currently planned and will be integrated: + +#. Mapping Configuration + Allowing to configure the whole mapping, to define type of input, e.g. integer, keyword. + + +#. Facets / Aggregates + Based on the mapping configuration, facets will be configurable and fetched. Therefore mapping is + required and we will adjust the result set to be of a custom model providing all information in a + more clean way. diff --git a/Documentation/source/index.rst b/Documentation/source/index.rst index dfda13b..5427fc9 100644 --- a/Documentation/source/index.rst +++ b/Documentation/source/index.rst @@ -7,6 +7,7 @@ Table of Contents :maxdepth: 1 :glob: + features installation configuration usage diff --git a/Documentation/source/usage.rst b/Documentation/source/usage.rst index 1fc0e51..453b17d 100644 --- a/Documentation/source/usage.rst +++ b/Documentation/source/usage.rst @@ -37,3 +37,30 @@ Searching / Frontend Plugin To provide a search interface you can insert the frontend Plugin as normal content element of type plugin. The plugin is named *Search Core*. + +Please provide your own template, the extension will not deliver a useful template for now. + +The extbase mapping is used, this way you can create a form: + +.. code-block:: html + + + + + + +.. _usage_searching_filter: + +Filter +"""""" + +Thanks to extbase mapping, filter are added to the form: + +.. code-block:: html + :emphasize-lines: 3 + + + + + + From aa8d7e36e6e9e8735a5b0ef3eb283d68c125347b Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Thu, 29 Jun 2017 09:13:39 +0200 Subject: [PATCH 10/20] TASK: Add test covering index command * To enable testing new configuration structure. --- Classes/Command/IndexCommandController.php | 4 +- .../Command/IndexCommandControllerTest.php | 106 ++++++++++++++++++ Tests/Unit/Domain/Search/QueryFactoryTest.php | 3 + 3 files changed, 110 insertions(+), 3 deletions(-) create mode 100644 Tests/Unit/Command/IndexCommandControllerTest.php diff --git a/Classes/Command/IndexCommandController.php b/Classes/Command/IndexCommandController.php index 55ac4df..78ee643 100644 --- a/Classes/Command/IndexCommandController.php +++ b/Classes/Command/IndexCommandController.php @@ -57,9 +57,7 @@ class IndexCommandController extends CommandController { // TODO: Allow to index multiple tables at once? // TODO: Also allow to index everything? - - // TODO: There is no test yet! - // TODO: Add test, adjust config path + // TODO: Adjust config path if (! in_array($table, GeneralUtility::trimExplode(',', $this->configuration->get('indexer.tca.allowedTables')))) { $this->outputLine('Table is not allowed for indexing.'); $this->quit(1); diff --git a/Tests/Unit/Command/IndexCommandControllerTest.php b/Tests/Unit/Command/IndexCommandControllerTest.php new file mode 100644 index 0000000..04e0dd0 --- /dev/null +++ b/Tests/Unit/Command/IndexCommandControllerTest.php @@ -0,0 +1,106 @@ + + * + * 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 Leonmrni\SearchCore\Command\IndexCommandController; +use Leonmrni\SearchCore\Configuration\ConfigurationContainerInterface; +use Leonmrni\SearchCore\Domain\Index\IndexerFactory; +use Leonmrni\SearchCore\Domain\Index\TcaIndexer; +use Leonmrni\SearchCore\Tests\Unit\AbstractUnitTestCase; +use TYPO3\CMS\Extbase\Mvc\Controller\CommandController; +use TYPO3\CMS\Extbase\Mvc\Exception\StopActionException; + +class IndexCommandControllerTest extends AbstractUnitTestCase +{ + /** + * @var IndexCommandController + */ + protected $subject; + + /** + * @var IndexerFactory + */ + protected $indexerFactory; + + public function setUp() + { + parent::setUp(); + + $this->indexerFactory = $this->getMockBuilder(IndexerFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $configuration = $this->getMockBuilder(ConfigurationContainerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $configuration->expects($this->once()) + ->method('get') + ->with('indexer.tca.allowedTables') + ->will($this->returnValue('allowedTable, anotherTable,YetAnotherTable')); + + $this->subject = $this->getMockBuilder(IndexCommandController::class) + ->disableOriginalConstructor() + ->setMethods(['quit', 'outputLine']) + ->getMock(); + $this->subject->injectIndexerFactory($this->indexerFactory); + $this->inject($this->subject, 'configuration', $configuration); + } + + /** + * @test + */ + public function indexerStopsForNonAllowedTable() + { + $this->expectException(StopActionException::class); + $this->subject->expects($this->once()) + ->method('quit') + ->with(1) + ->will($this->throwException(new StopActionException)); + + $this->subject->expects($this->once()) + ->method('outputLine') + ->with('Table is not allowed for indexing.'); + $this->indexerFactory->expects($this->never()) + ->method('getIndexer'); + + $this->subject->indexCommand('nonAllowedTable'); + } + + /** + * @test + */ + public function indexerExecutesForAllowedTable() + { + $indexerMock = $this->getMockBuilder(TcaIndexer::class) + ->disableOriginalConstructor() + ->getMock(); + $this->subject->expects($this->never()) + ->method('quit'); + $this->subject->expects($this->once()) + ->method('outputLine') + ->with('Table was indexed.'); + $this->indexerFactory->expects($this->once()) + ->method('getIndexer') + ->with('allowedTable') + ->will($this->returnValue($indexerMock)); + + $this->subject->indexCommand('allowedTable'); + } +} diff --git a/Tests/Unit/Domain/Search/QueryFactoryTest.php b/Tests/Unit/Domain/Search/QueryFactoryTest.php index 83f031e..9cb0a3d 100644 --- a/Tests/Unit/Domain/Search/QueryFactoryTest.php +++ b/Tests/Unit/Domain/Search/QueryFactoryTest.php @@ -27,6 +27,9 @@ use Leonmrni\SearchCore\Tests\Unit\AbstractUnitTestCase; class QueryFactoryTest extends AbstractUnitTestCase { + /** + * @var QueryFactory + */ protected $subject; public function setUp() From fde592f2e3f2258bb9c1330275cf0f3e6c1ab995 Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Thu, 29 Jun 2017 09:18:31 +0200 Subject: [PATCH 11/20] TASK: Adjust configuration for indexing * Adjust used configuration in command. --- Classes/Command/IndexCommandController.php | 3 +-- .../Command/IndexCommandControllerTest.php | 23 ++++++++++++++----- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/Classes/Command/IndexCommandController.php b/Classes/Command/IndexCommandController.php index 78ee643..aef0863 100644 --- a/Classes/Command/IndexCommandController.php +++ b/Classes/Command/IndexCommandController.php @@ -57,8 +57,7 @@ class IndexCommandController extends CommandController { // TODO: Allow to index multiple tables at once? // TODO: Also allow to index everything? - // TODO: Adjust config path - if (! in_array($table, GeneralUtility::trimExplode(',', $this->configuration->get('indexer.tca.allowedTables')))) { + if ($this->configuration->getIfExists('indexing.' . $table) === null) { $this->outputLine('Table is not allowed for indexing.'); $this->quit(1); } diff --git a/Tests/Unit/Command/IndexCommandControllerTest.php b/Tests/Unit/Command/IndexCommandControllerTest.php index 04e0dd0..c2559f9 100644 --- a/Tests/Unit/Command/IndexCommandControllerTest.php +++ b/Tests/Unit/Command/IndexCommandControllerTest.php @@ -40,6 +40,11 @@ class IndexCommandControllerTest extends AbstractUnitTestCase */ protected $indexerFactory; + /** + * @var ConfigurationContainerInterface + */ + protected $configuration; + public function setUp() { parent::setUp(); @@ -47,20 +52,16 @@ class IndexCommandControllerTest extends AbstractUnitTestCase $this->indexerFactory = $this->getMockBuilder(IndexerFactory::class) ->disableOriginalConstructor() ->getMock(); - $configuration = $this->getMockBuilder(ConfigurationContainerInterface::class) + $this->configuration = $this->getMockBuilder(ConfigurationContainerInterface::class) ->disableOriginalConstructor() ->getMock(); - $configuration->expects($this->once()) - ->method('get') - ->with('indexer.tca.allowedTables') - ->will($this->returnValue('allowedTable, anotherTable,YetAnotherTable')); $this->subject = $this->getMockBuilder(IndexCommandController::class) ->disableOriginalConstructor() ->setMethods(['quit', 'outputLine']) ->getMock(); $this->subject->injectIndexerFactory($this->indexerFactory); - $this->inject($this->subject, 'configuration', $configuration); + $this->inject($this->subject, 'configuration', $this->configuration); } /** @@ -80,6 +81,10 @@ class IndexCommandControllerTest extends AbstractUnitTestCase $this->indexerFactory->expects($this->never()) ->method('getIndexer'); + $this->configuration->expects($this->once()) + ->method('getIfExists') + ->with('indexing.nonAllowedTable') + ->will($this->returnValue(null)); $this->subject->indexCommand('nonAllowedTable'); } @@ -101,6 +106,12 @@ class IndexCommandControllerTest extends AbstractUnitTestCase ->with('allowedTable') ->will($this->returnValue($indexerMock)); + $this->configuration->expects($this->once()) + ->method('getIfExists') + ->with('indexing.allowedTable') + ->will($this->returnValue([ + 'indexer' => 'Leonmrni\SearchCore\Domain\Index\TcaIndexer', + ])); $this->subject->indexCommand('allowedTable'); } } From 03a953c13f055a61d13bf4762ca8527dee64b53e Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Tue, 4 Jul 2017 10:27:03 +0200 Subject: [PATCH 12/20] TASK: Add unit test covering configuration option Add test to cover option to configure user defined additionalWhereClause. --- .../Index/TcaIndexer/TcaTableService.php | 1 - .../Index/TcaIndexer/TcaTableServiceTest.php | 96 +++++++++++++++++++ 2 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 Tests/Unit/Domain/Index/TcaIndexer/TcaTableServiceTest.php diff --git a/Classes/Domain/Index/TcaIndexer/TcaTableService.php b/Classes/Domain/Index/TcaIndexer/TcaTableService.php index 7d69e5b..ae819bc 100644 --- a/Classes/Domain/Index/TcaIndexer/TcaTableService.php +++ b/Classes/Domain/Index/TcaIndexer/TcaTableService.php @@ -151,7 +151,6 @@ class TcaTableService . ' AND pages.no_search = 0' ; - // TODO: There is no test covering this option yet? $userDefinedWhere = $this->configuration->getIfExists('indexing.' . $this->getTableName() . '.additionalWhereClause'); if (is_string($userDefinedWhere)) { $whereClause .= ' AND ' . $userDefinedWhere; diff --git a/Tests/Unit/Domain/Index/TcaIndexer/TcaTableServiceTest.php b/Tests/Unit/Domain/Index/TcaIndexer/TcaTableServiceTest.php new file mode 100644 index 0000000..3a5b7fd --- /dev/null +++ b/Tests/Unit/Domain/Index/TcaIndexer/TcaTableServiceTest.php @@ -0,0 +1,96 @@ + + * + * 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 Leonmrni\SearchCore\Configuration\ConfigurationContainerInterface; +use Leonmrni\SearchCore\Domain\Index\TcaIndexer\TcaTableService; +use Leonmrni\SearchCore\Tests\Unit\AbstractUnitTestCase; + +class TcaTableServiceTest extends AbstractUnitTestCase +{ + /** + * @var TcaTableService + */ + protected $subject; + + /** + * @var ConfigurationContainerInterface + */ + protected $configuration; + + public function setUp() + { + parent::setUp(); + + $this->configuration = $this->getMockBuilder(ConfigurationContainerInterface::class)->getMock(); + $logger = $this->getMockBuilder(\TYPO3\CMS\Core\Log\LogManager::class) + ->disableOriginalConstructor() + ->setMethods(['getLogger']) + ->getMock(); + $logger->expects($this->once()) + ->method('getLogger') + ->will($this->returnValue( + $this->getMockBuilder(\TYPO3\CMS\Core\Log\Logger::class) + ->disableOriginalConstructor() + ->getMock() + )); + + $this->subject = $this->getMockBuilder(TcaTableService::class) + ->disableOriginalConstructor() + ->setMethodsExcept(['getWhereClause', 'injectLogger', 'getTableName']) + ->getMock(); + $this->inject($this->subject, 'configuration', $this->configuration); + $this->inject($this->subject, 'logger', $logger); + $this->inject($this->subject, 'tableName', 'table'); + } + + /** + * @test + */ + public function doUsePlainQueryIfNoAdditionalWhereClauseIsDefined() + { + $this->configuration->expects($this->exactly(2)) + ->method('getIfExists') + ->withConsecutive(['indexing.table.additionalWhereClause'], ['indexing.table.rootLineBlacklist']) + ->will($this->onConsecutiveCalls(null, false)); + + $this->assertSame( + '1=1 AND pages.no_search = 0', + $this->subject->getWhereClause() + ); + } + + /** + * @test + */ + public function configuredAdditionalWhereClauseIsAdded() + { + $this->configuration->expects($this->exactly(2)) + ->method('getIfExists') + ->withConsecutive(['indexing.table.additionalWhereClause'], ['indexing.table.rootLineBlacklist']) + ->will($this->onConsecutiveCalls('table.field = "someValue"', false)); + + $this->assertSame( + '1=1 AND pages.no_search = 0 AND table.field = "someValue"', + $this->subject->getWhereClause() + ); + } +} From 432335c80dce545dea133fe057b4ab0b12adeb65 Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Tue, 4 Jul 2017 12:12:36 +0200 Subject: [PATCH 13/20] FEATURE: Allow custom indexer Adjust code to use defined indexer as FQCN, to allow any class to be used as indexer. Also classes defined by user. --- Classes/Command/IndexCommandController.php | 24 ++-- Classes/Domain/Index/AbstractIndexer.php | 113 ++++++++++++++++++ Classes/Domain/Index/IndexerFactory.php | 62 ++++++++-- .../Index/NoMatchingIndexerException.php | 25 ++++ Classes/Domain/Index/TcaIndexer.php | 70 ++--------- Classes/Domain/Service/DataHandler.php | 60 ++++++---- Classes/Hook/DataHandler.php | 12 +- .../DataHandler/AbstractDataHandlerTest.php | 6 +- .../Command/IndexCommandControllerTest.php | 37 ++---- 9 files changed, 255 insertions(+), 154 deletions(-) create mode 100644 Classes/Domain/Index/AbstractIndexer.php create mode 100644 Classes/Domain/Index/NoMatchingIndexerException.php diff --git a/Classes/Command/IndexCommandController.php b/Classes/Command/IndexCommandController.php index aef0863..227918f 100644 --- a/Classes/Command/IndexCommandController.php +++ b/Classes/Command/IndexCommandController.php @@ -21,6 +21,7 @@ namespace Leonmrni\SearchCore\Command; */ use Leonmrni\SearchCore\Domain\Index\IndexerFactory; +use Leonmrni\SearchCore\Domain\Index\NoMatchingIndexerException; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Extbase\Mvc\Controller\CommandController; @@ -34,12 +35,6 @@ class IndexCommandController extends CommandController */ protected $indexerFactory; - /** - * @var \Leonmrni\SearchCore\Configuration\ConfigurationContainerInterface - * @inject - */ - protected $configuration; - /** * @param IndexerFactory $factory */ @@ -49,19 +44,18 @@ class IndexCommandController extends CommandController } /** - * Will index the given table or everything. + * Will index the given identifier. * - * @param string $table + * @param string $identifier */ - public function indexCommand($table) + public function indexCommand($identifier) { - // TODO: Allow to index multiple tables at once? // TODO: Also allow to index everything? - if ($this->configuration->getIfExists('indexing.' . $table) === null) { - $this->outputLine('Table is not allowed for indexing.'); - $this->quit(1); + try { + $this->indexerFactory->getIndexer($identifier)->indexAllDocuments(); + $this->outputLine($identifier . ' was indexed.'); + } catch (NoMatchingIndexerException $e) { + $this->outputLine('No indexer found for: ' . $identifier); } - $this->indexerFactory->getIndexer($table)->indexAllDocuments(); - $this->outputLine('Table was indexed.'); } } diff --git a/Classes/Domain/Index/AbstractIndexer.php b/Classes/Domain/Index/AbstractIndexer.php new file mode 100644 index 0000000..acd046e --- /dev/null +++ b/Classes/Domain/Index/AbstractIndexer.php @@ -0,0 +1,113 @@ + + * + * 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 Leonmrni\SearchCore\Connection\ConnectionInterface; + +abstract class AbstractIndexer implements IndexerInterface +{ + /** + * @var ConnectionInterface + */ + protected $connection; + + /** + * @var \TYPO3\CMS\Core\Log\Logger + */ + protected $logger; + + /** + * Inject log manager to get concrete logger from it. + * + * @param \TYPO3\CMS\Core\Log\LogManager $logManager + */ + public function injectLogger(\TYPO3\CMS\Core\Log\LogManager $logManager) + { + $this->logger = $logManager->getLogger(__CLASS__); + } + + /** + * @param ConnectionInterface $connection + */ + public function __construct(ConnectionInterface $connection) + { + $this->connection = $connection; + } + + public function indexAllDocuments() + { + $this->logger->info('Start indexing'); + foreach ($this->getRecordGenerator() as $records) { + $this->logger->debug('Index records.', [$records]); + if ($records === null) { + break; + } + + $this->connection->addDocuments($this->getDocumentName(), $records); + } + $this->logger->info('Finish indexing'); + } + + public function indexDocument($identifier) + { + $this->logger->info('Start indexing single record.', [$identifier]); + try { + $this->connection->addDocument($this->getDocumentName(), $this->getRecord($identifier)); + } catch (NoRecordFoundException $e) { + $this->logger->info('Could not index document.', [$e->getMessage()]); + } + $this->logger->info('Finish indexing'); + } + + /** + * @return \Generator + */ + protected function getRecordGenerator() + { + $offset = 0; + // TODO: Make configurable. + $limit = 50; + + while (($records = $this->getRecords($offset, $limit)) !== []) { + yield $records; + $offset += $limit; + } + } + + /** + * @param int $offset + * @param int $limit + * @return array|null + */ + abstract protected function getRecords($offset, $limit); + + /** + * @param int $identifier + * @return array + * @throws NoRecordFoundException If record could not be found. + */ + abstract protected function getRecord($identifier); + + /** + * @return string + */ + abstract protected function getDocumentName(); +} diff --git a/Classes/Domain/Index/IndexerFactory.php b/Classes/Domain/Index/IndexerFactory.php index 4ecbfb9..0140122 100644 --- a/Classes/Domain/Index/IndexerFactory.php +++ b/Classes/Domain/Index/IndexerFactory.php @@ -20,6 +20,11 @@ namespace Leonmrni\SearchCore\Domain\Index; * 02110-1301, USA. */ +use Leonmrni\SearchCore\Configuration\ConfigurationContainerInterface; +use Leonmrni\SearchCore\Configuration\InvalidArgumentException; +use Leonmrni\SearchCore\Domain\Index\IndexerInterface; +use Leonmrni\SearchCore\Domain\Index\TcaIndexer; +use Leonmrni\SearchCore\Domain\Index\TcaIndexer\TcaTableService; use TYPO3\CMS\Core\SingletonInterface as Singleton; use TYPO3\CMS\Extbase\Object\ObjectManagerInterface; @@ -33,28 +38,61 @@ class IndexerFactory implements Singleton */ protected $objectManager; + /** + * @var ConfigurationContainerInterface + */ + protected $configuration; + /** * @param ObjectManagerInterface $objectManager */ - public function __construct(ObjectManagerInterface $objectManager) - { + public function __construct( + ObjectManagerInterface $objectManager, + ConfigurationContainerInterface $configuration + ) { $this->objectManager = $objectManager; + $this->configuration = $configuration; } /** - * @param string $tableName + * @param string $identifier * * @return IndexerInterface + * @throws NoMatchingIndexer */ - public function getIndexer($tableName) + public function getIndexer($identifier) { - // This is the place to use configuration to return different indexer. - return $this->objectManager->get( - TcaIndexer::Class, - $this->objectManager->get( - TcaIndexer\TcaTableService::class, - $tableName - ) - ); + try { + return $this->buildIndexer($this->configuration->get('indexing.' . $identifier . '.indexer'), $identifier); + } catch (NoMatchingIndexerException $e) { + // Nothing to do, we throw exception below + } catch (InvalidArgumentException $e) { + // Nothing to do, we throw exception below + } + + throw new NoMatchingIndexerException('Could not find an indexer for ' . $identifier, 1497341442); + } + + /** + * @param string $indexerClass + * @param string $identifier + * + * @return IndexerInterface + * @throws NoMatchingIndexer + */ + protected function buildIndexer($indexerClass, $identifier) + { + if ($indexerClass === TcaIndexer::class) { + return $this->objectManager->get( + TcaIndexer::class, + $this->objectManager->get(TcaTableService::class, $identifier) + ); + } + + if (class_exists($indexerClass) && in_array(IndexerInterface::class, class_implements($indexerClass))) { + return $this->objectManager->get($indexerClass); + } + + throw new NoMatchingIndexerException('Could not find indexer: ' . $indexerClass, 1497341442); } } diff --git a/Classes/Domain/Index/NoMatchingIndexerException.php b/Classes/Domain/Index/NoMatchingIndexerException.php new file mode 100644 index 0000000..02904cc --- /dev/null +++ b/Classes/Domain/Index/NoMatchingIndexerException.php @@ -0,0 +1,25 @@ + + * + * 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. + */ + +class NoMatchingIndexerException extends IndexingException +{ +} diff --git a/Classes/Domain/Index/TcaIndexer.php b/Classes/Domain/Index/TcaIndexer.php index b50c6fa..52f1efa 100644 --- a/Classes/Domain/Index/TcaIndexer.php +++ b/Classes/Domain/Index/TcaIndexer.php @@ -26,33 +26,13 @@ use Leonmrni\SearchCore\Connection\ConnectionInterface; /** * Will index the given table using configuration from TCA. */ -class TcaIndexer implements IndexerInterface +class TcaIndexer extends AbstractIndexer { - /** - * @var ConnectionInterface - */ - protected $connection; - /** * @var TcaIndexer\TcaTableService */ protected $tcaTableService; - /** - * @var \TYPO3\CMS\Core\Log\Logger - */ - protected $logger; - - /** - * Inject log manager to get concrete logger from it. - * - * @param \TYPO3\CMS\Core\Log\LogManager $logManager - */ - public function injectLogger(\TYPO3\CMS\Core\Log\LogManager $logManager) - { - $this->logger = $logManager->getLogger(__CLASS__); - } - /** * @param TcaIndexer\TcaTableService $tcaTableService * @param ConnectionInterface $connection @@ -65,46 +45,6 @@ class TcaIndexer implements IndexerInterface $this->connection = $connection; } - public function indexAllDocuments() - { - $this->logger->info('Start indexing'); - foreach ($this->getRecordGenerator() as $records) { - $this->logger->debug('Index records.', [$records]); - if ($records === null) { - break; - } - - $this->connection->addDocuments($this->tcaTableService->getTableName(), $records); - } - $this->logger->info('Finish indexing'); - } - - public function indexDocument($identifier) - { - $this->logger->info('Start indexing single record.', [$identifier]); - try { - $this->connection->addDocument($this->tcaTableService->getTableName(), $this->getRecord($identifier)); - } catch (NoRecordFoundException $e) { - $this->logger->info('Could not index document.', [$e->getMessage()]); - } - $this->logger->info('Finish indexing'); - } - - /** - * @return \Generator - */ - protected function getRecordGenerator() - { - $offset = 0; - // TODO: Make configurable. - $limit = 50; - - while (($records = $this->getRecords($offset, $limit)) !== []) { - yield $records; - $offset += $limit; - } - } - /** * @param int $offset * @param int $limit @@ -156,4 +96,12 @@ class TcaIndexer implements IndexerInterface return $record; } + + /** + * @return string + */ + protected function getDocumentName() + { + return $this->tcaTableService->getTableName(); + } } diff --git a/Classes/Domain/Service/DataHandler.php b/Classes/Domain/Service/DataHandler.php index 578589a..bec9eb3 100644 --- a/Classes/Domain/Service/DataHandler.php +++ b/Classes/Domain/Service/DataHandler.php @@ -21,6 +21,8 @@ namespace Leonmrni\SearchCore\Domain\Service; */ use Leonmrni\SearchCore\Configuration\ConfigurationContainerInterface; +use Leonmrni\SearchCore\Domain\Index\IndexerFactory; +use Leonmrni\SearchCore\Domain\Index\NoMatchingIndexerException; use Leonmrni\SearchCore\Domain\Index\TcaIndexer; use TYPO3\CMS\Core\SingletonInterface as Singleton; use TYPO3\CMS\Core\Utility\GeneralUtility; @@ -47,8 +49,7 @@ class DataHandler implements Singleton protected $connection; /** - * @var \Leonmrni\SearchCore\Domain\Index\IndexerFactory - * @inject + * @var IndexerFactory */ protected $indexerFactory; @@ -74,30 +75,12 @@ class DataHandler implements Singleton /** * @param ConfigurationContainerInterface $configuration + * @param IndexerFactory $indexerFactory */ - public function __construct(ConfigurationContainerInterface $configuration) + public function __construct(ConfigurationContainerInterface $configuration, IndexerFactory $indexerFactory) { $this->configuration = $configuration; - } - - /** - * Get all tables that are allowed for indexing. - * - * @return array - */ - public function getAllowedTablesForIndexing() - { - $tables = []; - foreach ($this->configuration->get('indexing') as $tableName => $indexConfiguration) { - if ($indexConfiguration['indexer'] === TcaIndexer::class) { - $tables[] = $tableName; - continue; - } - // TODO: Support custom indexer. - // Define "interface" / option which is used. - } - - return $tables; + $this->indexerFactory = $indexerFactory; } /** @@ -107,7 +90,7 @@ class DataHandler implements Singleton public function add($table, array $record) { $this->logger->debug('Record received for add.', [$table, $record]); - $this->indexerFactory->getIndexer($table)->indexDocument($record['uid']); + $this->getIndexer($table)->indexDocument($record['uid']); } /** @@ -116,7 +99,7 @@ class DataHandler implements Singleton public function update($table, array $record) { $this->logger->debug('Record received for update.', [$table, $record]); - $this->indexerFactory->getIndexer($table)->indexDocument($record['uid']); + $this->getIndexer($table)->indexDocument($record['uid']); } /** @@ -128,4 +111,31 @@ class DataHandler implements Singleton $this->logger->debug('Record received for delete.', [$table, $identifier]); $this->connection->deleteDocument($table, $identifier); } + + /** + * @param string $table + * @return IndexerInterface + * + * @throws NoMatchingIndexerException + */ + protected function getIndexer($table) + { + return $this->indexerFactory->getIndexer($table); + } + + /** + * @param string $table + * @return bool + */ + public function canHandle($table) + { + try { + $this->getIndexer($table); + return true; + } catch (NoMatchingIndexerException $e) { + return false; + } + + return false; + } } diff --git a/Classes/Hook/DataHandler.php b/Classes/Hook/DataHandler.php index 1bcb4a5..34cf3f3 100644 --- a/Classes/Hook/DataHandler.php +++ b/Classes/Hook/DataHandler.php @@ -21,6 +21,7 @@ namespace Leonmrni\SearchCore\Hook; */ use Leonmrni\SearchCore\Configuration\NoConfigurationException; +use Leonmrni\SearchCore\Domain\Index\NoMatchingIndexerException; use Leonmrni\SearchCore\Domain\Service\DataHandler as OwnDataHandler; use TYPO3\CMS\Backend\Utility\BackendUtility; use TYPO3\CMS\Core\DataHandling\DataHandler as CoreDataHandler; @@ -140,7 +141,7 @@ class DataHandler implements Singleton $this->logger->debug('Datahandler could not be setup.'); return false; } - if (! $this->shouldProcessTable($table)) { + if (! $this->dataHandler->canHandle($table)) { $this->logger->debug('Table is not allowed.', [$table]); return false; } @@ -148,15 +149,6 @@ class DataHandler implements Singleton return true; } - /** - * @param string $table - * @return bool - */ - protected function shouldProcessTable($table) - { - return in_array($table, $this->dataHandler->getAllowedTablesForIndexing()); - } - /** * Wrapper to allow unit testing. * diff --git a/Tests/Functional/Hooks/DataHandler/AbstractDataHandlerTest.php b/Tests/Functional/Hooks/DataHandler/AbstractDataHandlerTest.php index a26021d..b3c384b 100644 --- a/Tests/Functional/Hooks/DataHandler/AbstractDataHandlerTest.php +++ b/Tests/Functional/Hooks/DataHandler/AbstractDataHandlerTest.php @@ -21,6 +21,7 @@ namespace Leonmrni\SearchCore\Tests\Functional\Hooks\DataHandler; */ use Leonmrni\SearchCore\Configuration\ConfigurationContainerInterface; +use Leonmrni\SearchCore\Domain\Index\IndexerFactory; use Leonmrni\SearchCore\Domain\Service\DataHandler as DataHandlerService; use Leonmrni\SearchCore\Hook\DataHandler as DataHandlerHook; use Leonmrni\SearchCore\Tests\Functional\AbstractFunctionalTestCase; @@ -42,7 +43,10 @@ abstract class AbstractDataHandlerTest extends AbstractFunctionalTestCase $objectManager = GeneralUtility::makeInstance(ObjectManager::class); $this->subject = $this->getMockBuilder(DataHandlerService::class) - ->setConstructorArgs([$objectManager->get(ConfigurationContainerInterface::class)]) + ->setConstructorArgs([ + $objectManager->get(ConfigurationContainerInterface::class), + $objectManager->get(IndexerFactory::class) + ]) ->setMethods(['add', 'update', 'delete']) ->getMock(); diff --git a/Tests/Unit/Command/IndexCommandControllerTest.php b/Tests/Unit/Command/IndexCommandControllerTest.php index c2559f9..3dff968 100644 --- a/Tests/Unit/Command/IndexCommandControllerTest.php +++ b/Tests/Unit/Command/IndexCommandControllerTest.php @@ -21,8 +21,8 @@ namespace Leonmrni\SearchCore\Tests\Unit\Command; */ use Leonmrni\SearchCore\Command\IndexCommandController; -use Leonmrni\SearchCore\Configuration\ConfigurationContainerInterface; use Leonmrni\SearchCore\Domain\Index\IndexerFactory; +use Leonmrni\SearchCore\Domain\Index\NoMatchingIndexerException; use Leonmrni\SearchCore\Domain\Index\TcaIndexer; use Leonmrni\SearchCore\Tests\Unit\AbstractUnitTestCase; use TYPO3\CMS\Extbase\Mvc\Controller\CommandController; @@ -40,11 +40,6 @@ class IndexCommandControllerTest extends AbstractUnitTestCase */ protected $indexerFactory; - /** - * @var ConfigurationContainerInterface - */ - protected $configuration; - public function setUp() { parent::setUp(); @@ -52,16 +47,12 @@ class IndexCommandControllerTest extends AbstractUnitTestCase $this->indexerFactory = $this->getMockBuilder(IndexerFactory::class) ->disableOriginalConstructor() ->getMock(); - $this->configuration = $this->getMockBuilder(ConfigurationContainerInterface::class) - ->disableOriginalConstructor() - ->getMock(); $this->subject = $this->getMockBuilder(IndexCommandController::class) ->disableOriginalConstructor() ->setMethods(['quit', 'outputLine']) ->getMock(); $this->subject->injectIndexerFactory($this->indexerFactory); - $this->inject($this->subject, 'configuration', $this->configuration); } /** @@ -69,22 +60,14 @@ class IndexCommandControllerTest extends AbstractUnitTestCase */ public function indexerStopsForNonAllowedTable() { - $this->expectException(StopActionException::class); - $this->subject->expects($this->once()) - ->method('quit') - ->with(1) - ->will($this->throwException(new StopActionException)); - $this->subject->expects($this->once()) ->method('outputLine') - ->with('Table is not allowed for indexing.'); - $this->indexerFactory->expects($this->never()) - ->method('getIndexer'); + ->with('No indexer found for: nonAllowedTable'); + $this->indexerFactory->expects($this->once()) + ->method('getIndexer') + ->with('nonAllowedTable') + ->will($this->throwException(new NoMatchingIndexerException)); - $this->configuration->expects($this->once()) - ->method('getIfExists') - ->with('indexing.nonAllowedTable') - ->will($this->returnValue(null)); $this->subject->indexCommand('nonAllowedTable'); } @@ -100,18 +83,12 @@ class IndexCommandControllerTest extends AbstractUnitTestCase ->method('quit'); $this->subject->expects($this->once()) ->method('outputLine') - ->with('Table was indexed.'); + ->with('allowedTable was indexed.'); $this->indexerFactory->expects($this->once()) ->method('getIndexer') ->with('allowedTable') ->will($this->returnValue($indexerMock)); - $this->configuration->expects($this->once()) - ->method('getIfExists') - ->with('indexing.allowedTable') - ->will($this->returnValue([ - 'indexer' => 'Leonmrni\SearchCore\Domain\Index\TcaIndexer', - ])); $this->subject->indexCommand('allowedTable'); } } From 975381cc4a25bb480b2ba6266b932139795c81d0 Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Thu, 6 Jul 2017 12:03:52 +0200 Subject: [PATCH 14/20] TASK: Integrate working code Copied code from customer installation with working implementation. --- .../ConfigurationContainerInterface.php | 2 + Classes/Connection/Elasticsearch.php | 40 +++++- Classes/Connection/Elasticsearch/Facet.php | 93 +++++++++++++ .../Connection/Elasticsearch/FacetOption.php | 61 +++++++++ .../Elasticsearch/MappingFactory.php | 73 +++++++++++ .../Connection/Elasticsearch/ResultItem.php | 56 ++++++++ .../Connection/Elasticsearch/SearchResult.php | 123 +++++++++++++++++- Classes/Connection/FacetInterface.php | 39 ++++++ Classes/Connection/FacetOptionInterface.php | 42 ++++++ Classes/Connection/FacetRequestInterface.php | 42 ++++++ Classes/Connection/ResultItemInterface.php | 29 +++++ Classes/Connection/SearchResultInterface.php | 14 +- Classes/Domain/Index/IndexerFactory.php | 1 + Classes/Domain/Index/TcaIndexer.php | 1 - Classes/Domain/Model/FacetRequest.php | 62 +++++++++ Classes/Domain/Model/SearchRequest.php | 28 +++- Classes/Domain/Search/QueryFactory.php | 103 ++++++++++++--- Classes/Domain/Search/SearchService.php | 56 +++++++- 18 files changed, 832 insertions(+), 33 deletions(-) create mode 100644 Classes/Connection/Elasticsearch/Facet.php create mode 100644 Classes/Connection/Elasticsearch/FacetOption.php create mode 100644 Classes/Connection/Elasticsearch/MappingFactory.php create mode 100644 Classes/Connection/Elasticsearch/ResultItem.php create mode 100644 Classes/Connection/FacetInterface.php create mode 100644 Classes/Connection/FacetOptionInterface.php create mode 100644 Classes/Connection/FacetRequestInterface.php create mode 100644 Classes/Connection/ResultItemInterface.php create mode 100644 Classes/Domain/Model/FacetRequest.php diff --git a/Classes/Configuration/ConfigurationContainerInterface.php b/Classes/Configuration/ConfigurationContainerInterface.php index 7bc45ef..d0d9828 100644 --- a/Classes/Configuration/ConfigurationContainerInterface.php +++ b/Classes/Configuration/ConfigurationContainerInterface.php @@ -34,6 +34,8 @@ interface ConfigurationContainerInterface extends Singleton * * @param string $path In dot notation. E.g. indexer.tca.allowedTables * @return mixed + * + * @throws InvalidArgumentException */ public function get($path); diff --git a/Classes/Connection/Elasticsearch.php b/Classes/Connection/Elasticsearch.php index 386e19c..88b93c2 100644 --- a/Classes/Connection/Elasticsearch.php +++ b/Classes/Connection/Elasticsearch.php @@ -20,8 +20,10 @@ namespace Leonmrni\SearchCore\Connection; * 02110-1301, USA. */ -use TYPO3\CMS\Core\SingletonInterface as Singleton; +use Leonmrni\SearchCore\Connection\Elasticsearch\SearchResult; use Leonmrni\SearchCore\Domain\Search\QueryFactory; +use TYPO3\CMS\Core\SingletonInterface as Singleton; +use TYPO3\CMS\Extbase\Object\ObjectManagerInterface; /** * Outer wrapper to elasticsearch. @@ -43,6 +45,11 @@ class Elasticsearch implements Singleton, ConnectionInterface */ protected $typeFactory; + /** + * @var Elasticsearch\MappingFactory + */ + protected $mappingFactory; + /** * @var Elasticsearch\DocumentFactory */ @@ -58,6 +65,11 @@ class Elasticsearch implements Singleton, ConnectionInterface */ protected $logger; + /** + * @var ObjectManagerInterface + */ + protected $objectManager; + /** * Inject log manager to get concrete logger from it. * @@ -68,10 +80,19 @@ class Elasticsearch implements Singleton, ConnectionInterface $this->logger = $logManager->getLogger(__CLASS__); } + /** + * @param ObjectManagerInterface $objectManager + */ + public function injectObjectManager(ObjectManagerInterface $objectManager) + { + $this->objectManager = $objectManager; + } + /** * @param Elasticsearch\Connection $connection * @param Elasticsearch\IndexFactory $indexFactory * @param Elasticsearch\TypeFactory $typeFactory + * @param Elasticsearch\MappingFactory $mappingFactory * @param Elasticsearch\DocumentFactory $documentFactory * @param QueryFactory $queryFactory */ @@ -79,12 +100,14 @@ class Elasticsearch implements Singleton, ConnectionInterface Elasticsearch\Connection $connection, Elasticsearch\IndexFactory $indexFactory, Elasticsearch\TypeFactory $typeFactory, + Elasticsearch\MappingFactory $mappingFactory, Elasticsearch\DocumentFactory $documentFactory, QueryFactory $queryFactory ) { $this->connection = $connection; $this->indexFactory = $indexFactory; $this->typeFactory = $typeFactory; + $this->mappingFactory = $mappingFactory; $this->documentFactory = $documentFactory; $this->queryFactory = $queryFactory; } @@ -142,6 +165,13 @@ class Elasticsearch implements Singleton, ConnectionInterface protected function withType($documentType, callable $callback) { $type = $this->getType($documentType); + // TODO: Check whether it's to heavy to send it so often e.g. for every single document. + // Perhaps add command controller to submit mapping?! + // Also it's not possible to change mapping without deleting index first. + // Mattes told about a solution. + // So command looks like the best way so far, except we manage mattes solution. + // Still then this should be done once. So perhaps singleton which tracks state and does only once? + $this->mappingFactory->getMapping($type)->send(); $callback($type); $type->getIndex()->refresh(); } @@ -149,7 +179,7 @@ class Elasticsearch implements Singleton, ConnectionInterface /** * @param SearchRequestInterface $searchRequest * - * @return \Elastica\ResultSet + * @return SearchResultInterface */ public function search(SearchRequestInterface $searchRequest) { @@ -157,11 +187,9 @@ class Elasticsearch implements Singleton, ConnectionInterface $search = new \Elastica\Search($this->connection->getClient()); $search->addIndex('typo3content'); - $search->setQuery($this->queryFactory->create($this, $searchRequest)); + $search->setQuery($this->queryFactory->create($searchRequest)); - // TODO: Return wrapped result to implement our interface. - // Also update php doc to reflect the change. - return $search->search(); + return $this->objectManager->get(SearchResult::class, $search->search()); } /** diff --git a/Classes/Connection/Elasticsearch/Facet.php b/Classes/Connection/Elasticsearch/Facet.php new file mode 100644 index 0000000..79a87b3 --- /dev/null +++ b/Classes/Connection/Elasticsearch/Facet.php @@ -0,0 +1,93 @@ + + * + * 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 Leonmrni\SearchCore\Configuration\ConfigurationContainerInterface; +use Leonmrni\SearchCore\Connection\FacetInterface; + +class Facet implements FacetInterface +{ + /** + * @var string + */ + protected $name = ''; + + /** + * @var string + */ + protected $field = ''; + + /** + * @var array + */ + protected $buckets = []; + + /** + * @var array + */ + protected $options = []; + + public function __construct($name, array $aggregation, ConfigurationContainerInterface $configuration) + { + $this->name = $name; + $this->buckets = $aggregation['buckets']; + $this->field = $configuration->getIfExists('searching.facets.' . $this->name . '.field') ?: ''; + } + + /** + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * @return string + */ + public function getField() + { + return $this->field; + } + + /** + * Returns all possible options for this facet. + * + * @return array + */ + public function getOptions() + { + $this->initOptions(); + + return $this->options; + } + + protected function initOptions() + { + if ($this->options !== []) { + return; + } + + foreach ($this->buckets as $bucket) { + $this->options[] = new FacetOption($bucket); + } + } +} diff --git a/Classes/Connection/Elasticsearch/FacetOption.php b/Classes/Connection/Elasticsearch/FacetOption.php new file mode 100644 index 0000000..a618be1 --- /dev/null +++ b/Classes/Connection/Elasticsearch/FacetOption.php @@ -0,0 +1,61 @@ + + * + * 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 Leonmrni\SearchCore\Connection\FacetOptionInterface; + +class FacetOption implements FacetOptionInterface +{ + /** + * @var string + */ + protected $name = ''; + + /** + * @var int + */ + protected $count = 0; + + /** + * @param array $bucket + */ + public function __construct(array $bucket) + { + $this->name = $bucket['key']; + $this->count = $bucket['doc_count']; + } + + /** + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * @return int + */ + public function getCount() + { + return $this->count; + } +} diff --git a/Classes/Connection/Elasticsearch/MappingFactory.php b/Classes/Connection/Elasticsearch/MappingFactory.php new file mode 100644 index 0000000..f029cd1 --- /dev/null +++ b/Classes/Connection/Elasticsearch/MappingFactory.php @@ -0,0 +1,73 @@ + + * + * 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 Leonmrni\SearchCore\Configuration\ConfigurationContainerInterface; +use Leonmrni\SearchCore\Configuration\InvalidArgumentException; +use TYPO3\CMS\Core\SingletonInterface as Singleton; + +/** + * Factory to get mappings. + */ +class MappingFactory implements Singleton +{ + /** + * @var ConfigurationContainerInterface + */ + protected $configuration; + + /** + * @param ConfigurationContainerInterface $configuration + */ + public function __construct(ConfigurationContainerInterface $configuration) + { + $this->configuration = $configuration; + } + + /** + * Get an mapping based on type. + * + * @param \Elastica\Type $type + * + * @return \Elastica\Mapping + */ + public function getMapping(\Elastica\Type $type) + { + $mapping = new \Elastica\Type\Mapping(); + $mapping->setType($type); + $mapping->setProperties($this->getConfiguration($type->getName())); + + return $mapping; + } + + /** + * @param string $identifier + * @return array + */ + protected function getConfiguration($identifier) + { + try { + return $this->configuration->get('indexing.' . $identifier . '.mapping'); + } catch (InvalidArgumentException $e) { + return []; + } + } +} diff --git a/Classes/Connection/Elasticsearch/ResultItem.php b/Classes/Connection/Elasticsearch/ResultItem.php new file mode 100644 index 0000000..dd8cb62 --- /dev/null +++ b/Classes/Connection/Elasticsearch/ResultItem.php @@ -0,0 +1,56 @@ + + * + * 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 Leonmrni\SearchCore\Connection\ResultItemInterface; + +class ResultItem implements ResultItemInterface +{ + /** + * @var array + */ + protected $data = []; + + public function __construct(\Elastica\Result $result) + { + $this->data = $result->getData(); + } + + public function offsetExists($offset) + { + return isset($this->data[$offset]); + } + + public function offsetGet($offset) + { + return $this->data[$offset]; + } + + public function offsetSet() + { + throw new \BadMethodCallException('It\'s not possible to change the search result.', 1499179077); + } + + public function offsetUnset() + { + throw new \BadMethodCallException('It\'s not possible to change the search result.', 1499179077); + } +} diff --git a/Classes/Connection/Elasticsearch/SearchResult.php b/Classes/Connection/Elasticsearch/SearchResult.php index 3f90d60..63c93b0 100644 --- a/Classes/Connection/Elasticsearch/SearchResult.php +++ b/Classes/Connection/Elasticsearch/SearchResult.php @@ -20,12 +20,127 @@ namespace Leonmrni\SearchCore\Connection\Elasticsearch; * 02110-1301, USA. */ +use Leonmrni\SearchCore\Connection\FacetInterface; +use Leonmrni\SearchCore\Connection\ResultItemInterface; use Leonmrni\SearchCore\Connection\SearchResultInterface; +use TYPO3\CMS\Extbase\Object\ObjectManagerInterface; -/** - * - */ -class SearchResult extends \Elastica\SearchResult implements SearchResultInterface +class SearchResult implements SearchResultInterface { + /** + * @var \Elastica\ResultSet + */ + protected $result; + /** + * @var array + */ + protected $facets = []; + + /** + * @var array + */ + protected $results = []; + + /** + * @var ObjectManagerInterface + */ + protected $objectManager; + + public function __construct(\Elastica\ResultSet $result, ObjectManagerInterface $objectManager) + { + $this->result = $result; + $this->objectManager = $objectManager; + } + + /** + * @return array + */ + public function getResults() + { + $this->initResults(); + + return $this->results; + } + + /** + * Return all facets, if any. + * + * @return array + */ + public function getFacets() + { + $this->initFacets(); + + return $this->facets; + } + + /** + * Returns the total sum of matching results. + * + * @return int + */ + public function getTotalCount() + { + return $this->result->getTotalHits(); + } + + // Countable - Interface + /** + * Returns the total sum of results contained in this result. + * + * @return int + */ + public function count() + { + return $this->result->count(); + } + + // Iterator - Interface + public function current() + { + return $this->result->current(); + } + + public function next() + { + return $this->result->next(); + } + + public function key() + { + return $this->result->key(); + } + + public function valid() + { + return $this->result->valid(); + } + + public function rewind() + { + $this->result->rewind(); + } + + protected function initResults() + { + if ($this->results !== []) { + return; + } + + foreach ($this->result->getResults() as $result) { + $this->results[] = new ResultItem($result); + } + } + + protected function initFacets() + { + if ($this->facets !== [] || !$this->result->hasAggregations()) { + return; + } + + foreach ($this->result->getAggregations() as $aggregationName => $aggregation) { + $this->facets[] = $this->objectManager->get(Facet::class, $aggregationName, $aggregation); + } + } } diff --git a/Classes/Connection/FacetInterface.php b/Classes/Connection/FacetInterface.php new file mode 100644 index 0000000..f422e98 --- /dev/null +++ b/Classes/Connection/FacetInterface.php @@ -0,0 +1,39 @@ + + * + * 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. + */ + +/** + * A single facet, e.g. keyword based. + */ +interface FacetInterface +{ + /** + * @return string + */ + public function getName(); + + /** + * Returns all possible options for this facet. + * + * @return array + */ + public function getOptions(); +} diff --git a/Classes/Connection/FacetOptionInterface.php b/Classes/Connection/FacetOptionInterface.php new file mode 100644 index 0000000..b05445b --- /dev/null +++ b/Classes/Connection/FacetOptionInterface.php @@ -0,0 +1,42 @@ + + * + * 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. + */ + +/** + * A single possible option of a facet. + */ +interface FacetOptionInterface +{ + /** + * Returns the name of this option. Equivalent + * to value used for filtering. + * + * @return string + */ + public function getName(); + + /** + * Returns the number of found results for this option. + * + * @return int + */ + public function getCount(); +} diff --git a/Classes/Connection/FacetRequestInterface.php b/Classes/Connection/FacetRequestInterface.php new file mode 100644 index 0000000..e5a60a1 --- /dev/null +++ b/Classes/Connection/FacetRequestInterface.php @@ -0,0 +1,42 @@ + + * + * 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. + */ + +/** + * Used to request facets / aggregates from connection. + */ +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(); + + /** + * The field to use for facet building. + * + * @return string + */ + public function getField(); +} diff --git a/Classes/Connection/ResultItemInterface.php b/Classes/Connection/ResultItemInterface.php new file mode 100644 index 0000000..f4c9185 --- /dev/null +++ b/Classes/Connection/ResultItemInterface.php @@ -0,0 +1,29 @@ + + * + * 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 ArrayAccess to enable retrieval of information in fluid. + */ +interface ResultItemInterface extends \ArrayAccess +{ + +} diff --git a/Classes/Connection/SearchResultInterface.php b/Classes/Connection/SearchResultInterface.php index f00e97c..a6b2c90 100644 --- a/Classes/Connection/SearchResultInterface.php +++ b/Classes/Connection/SearchResultInterface.php @@ -21,9 +21,19 @@ namespace Leonmrni\SearchCore\Connection; */ /** - * + * A search result. */ -interface SearchResultInterface extends \Iterator, \Countable, \ArrayAccess +interface SearchResultInterface extends \Iterator, \Countable { + /** + * @return array + */ + public function getResults(); + /** + * Return all facets, if any. + * + * @return array + */ + public function getFacets(); } diff --git a/Classes/Domain/Index/IndexerFactory.php b/Classes/Domain/Index/IndexerFactory.php index 0140122..24addd1 100644 --- a/Classes/Domain/Index/IndexerFactory.php +++ b/Classes/Domain/Index/IndexerFactory.php @@ -45,6 +45,7 @@ class IndexerFactory implements Singleton /** * @param ObjectManagerInterface $objectManager + * @param ConfigurationContainerInterface $configuration */ public function __construct( ObjectManagerInterface $objectManager, diff --git a/Classes/Domain/Index/TcaIndexer.php b/Classes/Domain/Index/TcaIndexer.php index 52f1efa..17dc61e 100644 --- a/Classes/Domain/Index/TcaIndexer.php +++ b/Classes/Domain/Index/TcaIndexer.php @@ -20,7 +20,6 @@ namespace Leonmrni\SearchCore\Domain\Index; * 02110-1301, USA. */ -use TYPO3\CMS\Extbase\Object\ObjectManagerInterface; use Leonmrni\SearchCore\Connection\ConnectionInterface; /** diff --git a/Classes/Domain/Model/FacetRequest.php b/Classes/Domain/Model/FacetRequest.php new file mode 100644 index 0000000..715e74a --- /dev/null +++ b/Classes/Domain/Model/FacetRequest.php @@ -0,0 +1,62 @@ + + * + * 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 Leonmrni\SearchCore\Connection\FacetRequestInterface; + +class FacetRequest implements FacetRequestInterface +{ + /** + * @var string + */ + protected $identifier = ''; + + /** + * @var string + */ + protected $field = ''; + + /** + * @param string $identifier + * @param string $field + */ + public function __construct($identifier, $field) + { + $this->identifier = $identifier; + $this->field = $field; + } + + /** + * @return string + */ + public function getIdentifier() + { + return $this->identifier; + } + + /** + * @return string + */ + public function getField() + { + return $this->field; + } +} diff --git a/Classes/Domain/Model/SearchRequest.php b/Classes/Domain/Model/SearchRequest.php index f1ad18e..65ab979 100644 --- a/Classes/Domain/Model/SearchRequest.php +++ b/Classes/Domain/Model/SearchRequest.php @@ -20,6 +20,7 @@ namespace Leonmrni\SearchCore\Domain\Model; * 02110-1301, USA. */ +use Leonmrni\SearchCore\Connection\FacetRequestInterface; use Leonmrni\SearchCore\Connection\SearchRequestInterface; /** @@ -39,6 +40,11 @@ class SearchRequest implements SearchRequestInterface */ protected $filter = []; + /** + * @var array + */ + protected $facets = []; + /** * @param string $query */ @@ -68,7 +74,7 @@ class SearchRequest implements SearchRequestInterface */ public function setFilter(array $filter) { - $this->filter = array_map('strval', $filter); + $this->filter = array_filter(array_map('strval', $filter)); } /** @@ -86,4 +92,24 @@ class SearchRequest implements SearchRequestInterface { return $this->filter; } + + /** + * Add a facet to gather in this search request. + * + * @param FacetRequestInterface $facet + */ + public function addFacet(FacetRequestInterface $facet) + { + $this->facets[$facet->getIdentifier()] = $facet; + } + + /** + * Returns all configured facets to fetch in this search request. + * + * @return array + */ + public function getFacets() + { + return $this->facets; + } } diff --git a/Classes/Domain/Search/QueryFactory.php b/Classes/Domain/Search/QueryFactory.php index 31c50df..778b575 100644 --- a/Classes/Domain/Search/QueryFactory.php +++ b/Classes/Domain/Search/QueryFactory.php @@ -23,44 +23,117 @@ namespace Leonmrni\SearchCore\Domain\Search; use Leonmrni\SearchCore\Connection\ConnectionInterface; use Leonmrni\SearchCore\Connection\Elasticsearch\Query; use Leonmrni\SearchCore\Connection\SearchRequestInterface; +use TYPO3\CMS\Extbase\Utility\ArrayUtility; class QueryFactory { /** - * @param ConnectionInterface $connection + * @var \TYPO3\CMS\Core\Log\Logger + */ + protected $logger; + + /** + * @var array + */ + protected $query = []; + + /** + * @param \TYPO3\CMS\Core\Log\LogManager $logManager + */ + public function __construct(\TYPO3\CMS\Core\Log\LogManager $logManager) + { + $this->logger = $logManager->getLogger(__CLASS__); + } + + /** * @param SearchRequestInterface $searchRequest * * @return \Elastica\Query */ - public function create( - ConnectionInterface $connection, - SearchRequestInterface $searchRequest - ) { + public function create(SearchRequestInterface $searchRequest) + { return $this->createElasticaQuery($searchRequest); } /** * @param SearchRequestInterface $searchRequest + * + * TODO: This is not in scope Elasticsearch, therefore should not return elastica. * @return \Elastica\Query */ protected function createElasticaQuery(SearchRequestInterface $searchRequest) { - $query = [ - 'bool' => [ - 'must' => [ - [ - 'match' => [ - '_all' => $searchRequest->getSearchTerm() + $this->addSearch($searchRequest); + $this->addFilter($searchRequest); + $this->addFacets($searchRequest); + + // TODO: Add logging here. + $this->logger->debug('Generated elasticsearch query.', [$this->query]); + return new \Elastica\Query($this->query); + } + + /** + * @param SearchRequestInterface $searchRequest + */ + protected function addSearch(SearchRequestInterface $searchRequest) + { + $this->query = ArrayUtility::arrayMergeRecursiveOverrule($this->query, [ + 'query' => [ + 'bool' => [ + 'must' => [ + [ + 'match' => [ + '_all' => $searchRequest->getSearchTerm() + ], ], ], ], ], - ]; + ]); + } - if ($searchRequest->hasFilter()) { - $query['bool']['filter'] = ['term' => $searchRequest->getFilter()]; + /** + * @param SearchRequestInterface $searchRequest + */ + protected function addFilter(SearchRequestInterface $searchRequest) + { + if (! $searchRequest->hasFilter()) { + return; } - return new \Elastica\Query(['query' => $query]); + $terms = []; + foreach ($searchRequest->getFilter() as $name => $value) { + $terms[] = [ + 'term' => [ + $name => $value, + ], + ]; + } + + $this->query = ArrayUtility::arrayMergeRecursiveOverrule($this->query, [ + 'query' => [ + 'bool' => [ + 'filter' => $terms, + ], + ], + ]); + } + + /** + * @param SearchRequestInterface $searchRequest + */ + protected function addFacets(SearchRequestInterface $searchRequest) + { + foreach ($searchRequest->getFacets() as $facet) { + $this->query = ArrayUtility::arrayMergeRecursiveOverrule($this->query, [ + 'aggs' => [ + $facet->getIdentifier() => [ + 'terms' => [ + 'field' => $facet->getField(), + ], + ], + ], + ]); + } } } diff --git a/Classes/Domain/Search/SearchService.php b/Classes/Domain/Search/SearchService.php index afbaf7e..ac991cd 100644 --- a/Classes/Domain/Search/SearchService.php +++ b/Classes/Domain/Search/SearchService.php @@ -20,10 +20,13 @@ namespace Leonmrni\SearchCore\Domain\Search; * 02110-1301, USA. */ +use Leonmrni\SearchCore\Configuration\ConfigurationContainerInterface; +use Leonmrni\SearchCore\Configuration\InvalidArgumentException; use Leonmrni\SearchCore\Connection\ConnectionInterface; use Leonmrni\SearchCore\Connection\SearchRequestInterface; use Leonmrni\SearchCore\Connection\SearchResultInterface; -use Leonmrni\SearchCore\Domain\Model\SearchRequest; +use Leonmrni\SearchCore\Domain\Model\FacetRequest; +use TYPO3\CMS\Extbase\Object\ObjectManagerInterface; /** * Service to process a search request. @@ -36,11 +39,28 @@ class SearchService protected $connection; /** - * @param ConnectionInterface $connection + * @var ConfigurationContainerInterface */ - public function __construct(ConnectionInterface $connection) - { + protected $configuration; + + /** + * @var ObjectManagerInterface + */ + protected $objectManager; + + /** + * @param ConnectionInterface $connection + * @param ConfigurationContainerInterface $configuration + * @param ObjectManagerInterface $objectManager + */ + public function __construct( + ConnectionInterface $connection, + ConfigurationContainerInterface $configuration, + ObjectManagerInterface $objectManager + ) { $this->connection = $connection; + $this->configuration = $configuration; + $this->objectManager = $objectManager; } /** @@ -49,6 +69,34 @@ class SearchService */ public function search(SearchRequestInterface $searchRequest) { + $this->addConfiguredFacets($searchRequest); + return $this->connection->search($searchRequest); } + + /** + * Add facets from configuration to request. + * + * @param SearchRequestInterface $searchRequest + */ + protected function addConfiguredFacets(SearchRequestInterface $searchRequest) + { + $facetsConfig = $this->configuration->getIfExists('searching.facets'); + if ($facetsConfig === null) { + return; + } + + 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'] + )); + } + } } From 05f846a1cfc2a6b0b04cfaa726ee6225ae151646 Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Thu, 6 Jul 2017 13:53:29 +0200 Subject: [PATCH 15/20] Update existing unit tests Make existing unit tests work with new code base. Also add new tests for new code to existing tests. --- Classes/Domain/Model/FacetRequest.php | 4 + Classes/Domain/Search/QueryFactory.php | 1 - Tests/Unit/AbstractUnitTestCase.php | 19 +++++ .../Index/TcaIndexer/TcaTableServiceTest.php | 13 +-- Tests/Unit/Domain/Search/QueryFactoryTest.php | 80 +++++++++++++++---- 5 files changed, 87 insertions(+), 30 deletions(-) diff --git a/Classes/Domain/Model/FacetRequest.php b/Classes/Domain/Model/FacetRequest.php index 715e74a..5b8bea6 100644 --- a/Classes/Domain/Model/FacetRequest.php +++ b/Classes/Domain/Model/FacetRequest.php @@ -35,6 +35,10 @@ class FacetRequest implements FacetRequestInterface protected $field = ''; /** + * 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 */ diff --git a/Classes/Domain/Search/QueryFactory.php b/Classes/Domain/Search/QueryFactory.php index 778b575..70f42ff 100644 --- a/Classes/Domain/Search/QueryFactory.php +++ b/Classes/Domain/Search/QueryFactory.php @@ -67,7 +67,6 @@ class QueryFactory $this->addFilter($searchRequest); $this->addFacets($searchRequest); - // TODO: Add logging here. $this->logger->debug('Generated elasticsearch query.', [$this->query]); return new \Elastica\Query($this->query); } diff --git a/Tests/Unit/AbstractUnitTestCase.php b/Tests/Unit/AbstractUnitTestCase.php index f3281c1..88496a1 100644 --- a/Tests/Unit/AbstractUnitTestCase.php +++ b/Tests/Unit/AbstractUnitTestCase.php @@ -24,4 +24,23 @@ use TYPO3\CMS\Core\Tests\UnitTestCase as CoreTestCase; abstract class AbstractUnitTestCase extends CoreTestCase { + /** + * @return \TYPO3\CMS\Core\Log\LogManager + */ + protected function getMockedLogger() + { + $logger = $this->getMockBuilder(\TYPO3\CMS\Core\Log\LogManager::class) + ->disableOriginalConstructor() + ->setMethods(['getLogger']) + ->getMock(); + $logger->expects($this->once()) + ->method('getLogger') + ->will($this->returnValue( + $this->getMockBuilder(\TYPO3\CMS\Core\Log\Logger::class) + ->disableOriginalConstructor() + ->getMock() + )); + + return $logger; + } } diff --git a/Tests/Unit/Domain/Index/TcaIndexer/TcaTableServiceTest.php b/Tests/Unit/Domain/Index/TcaIndexer/TcaTableServiceTest.php index 3a5b7fd..837d68c 100644 --- a/Tests/Unit/Domain/Index/TcaIndexer/TcaTableServiceTest.php +++ b/Tests/Unit/Domain/Index/TcaIndexer/TcaTableServiceTest.php @@ -41,24 +41,13 @@ class TcaTableServiceTest extends AbstractUnitTestCase parent::setUp(); $this->configuration = $this->getMockBuilder(ConfigurationContainerInterface::class)->getMock(); - $logger = $this->getMockBuilder(\TYPO3\CMS\Core\Log\LogManager::class) - ->disableOriginalConstructor() - ->setMethods(['getLogger']) - ->getMock(); - $logger->expects($this->once()) - ->method('getLogger') - ->will($this->returnValue( - $this->getMockBuilder(\TYPO3\CMS\Core\Log\Logger::class) - ->disableOriginalConstructor() - ->getMock() - )); $this->subject = $this->getMockBuilder(TcaTableService::class) ->disableOriginalConstructor() ->setMethodsExcept(['getWhereClause', 'injectLogger', 'getTableName']) ->getMock(); $this->inject($this->subject, 'configuration', $this->configuration); - $this->inject($this->subject, 'logger', $logger); + $this->inject($this->subject, 'logger', $this->getMockedLogger()); $this->inject($this->subject, 'tableName', 'table'); } diff --git a/Tests/Unit/Domain/Search/QueryFactoryTest.php b/Tests/Unit/Domain/Search/QueryFactoryTest.php index 9cb0a3d..725754f 100644 --- a/Tests/Unit/Domain/Search/QueryFactoryTest.php +++ b/Tests/Unit/Domain/Search/QueryFactoryTest.php @@ -20,7 +20,7 @@ namespace Leonmrni\SearchCore\Tests\Unit\Domain\Search; * 02110-1301, USA. */ -use Leonmrni\SearchCore\Connection; +use Leonmrni\SearchCore\Domain\Model\FacetRequest; use Leonmrni\SearchCore\Domain\Model\SearchRequest; use Leonmrni\SearchCore\Domain\Search\QueryFactory; use Leonmrni\SearchCore\Tests\Unit\AbstractUnitTestCase; @@ -36,7 +36,7 @@ class QueryFactoryTest extends AbstractUnitTestCase { parent::setUp(); - $this->subject = new QueryFactory; + $this->subject = new QueryFactory($this->getMockedLogger()); } /** @@ -44,12 +44,9 @@ class QueryFactoryTest extends AbstractUnitTestCase */ public function creatonOfQueryWorksInGeneral() { - $connection = $this->getMockBuilder(Connection\Elasticsearch::class) - ->disableOriginalConstructor() - ->getMock(); $searchRequest = new SearchRequest('SearchWord'); - $query = $this->subject->create($connection, $searchRequest); + $query = $this->subject->create($searchRequest); $this->assertInstanceOf( \Elastica\Query::class, $query, @@ -62,32 +59,53 @@ class QueryFactoryTest extends AbstractUnitTestCase */ public function filterIsAddedToQuery() { - $connection = $this->getMockBuilder(Connection\Elasticsearch::class) - ->disableOriginalConstructor() - ->getMock(); $searchRequest = new SearchRequest('SearchWord'); $searchRequest->setFilter(['field' => 'content']); - $query = $this->subject->create($connection, $searchRequest); + $query = $this->subject->create($searchRequest); $this->assertSame( - ['field' => 'content'], - $query->toArray()['query']['bool']['filter']['term'], + [ + ['term' => ['field' => 'content']] + ], + $query->toArray()['query']['bool']['filter'], 'Filter was not added to query.' ); } + /** + * @test + */ + public function emptyFilterIsNotAddedToQuery() + { + $searchRequest = new SearchRequest('SearchWord'); + $searchRequest->setFilter([ + 'field' => '', + 'field1' => 0, + 'field2' => false, + ]); + + $this->assertFalse( + $searchRequest->hasFilter(), + 'Search request contains filter even if it should not.' + ); + + $query = $this->subject->create($searchRequest); + $this->assertSame( + null, + $query->toArray()['query']['bool']['filter'], + 'Filter was added to query, even if no filter exists.' + ); + } + /** * @test */ public function userInputIsAlwaysString() { - $connection = $this->getMockBuilder(Connection\Elasticsearch::class) - ->disableOriginalConstructor() - ->getMock(); $searchRequest = new SearchRequest(10); $searchRequest->setFilter(['field' => 20]); - $query = $this->subject->create($connection, $searchRequest); + $query = $this->subject->create($searchRequest); $this->assertSame( '10', $query->toArray()['query']['bool']['must'][0]['match']['_all'], @@ -95,8 +113,36 @@ class QueryFactoryTest extends AbstractUnitTestCase ); $this->assertSame( '20', - $query->toArray()['query']['bool']['filter']['term']['field'], + $query->toArray()['query']['bool']['filter'][0]['term']['field'], 'Search word was not escaped as expected.' ); } + + /** + * @test + */ + public function facetsAreAddedToQuery() + { + $searchRequest = new SearchRequest('SearchWord'); + $searchRequest->addFacet(new FacetRequest('Identifier', 'FieldName')); + $searchRequest->addFacet(new FacetRequest('Identifier 2', 'FieldName 2')); + + $query = $this->subject->create($searchRequest); + $this->assertSame( + [ + 'Identifier' => [ + 'terms' => [ + 'field' => 'FieldName', + ], + ], + 'Identifier 2' => [ + 'terms' => [ + 'field' => 'FieldName 2', + ], + ], + ], + $query->toArray()['aggs'], + 'Facets were not added to query.' + ); + } } From c6a199a7a47a6fefb7184eb4419fa311e37e481e Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Thu, 6 Jul 2017 14:13:26 +0200 Subject: [PATCH 16/20] BUGFIX: Fix broken functional test --- Classes/Connection/Elasticsearch/ResultItem.php | 4 ++-- Tests/Functional/Connection/Elasticsearch/FilterTest.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Classes/Connection/Elasticsearch/ResultItem.php b/Classes/Connection/Elasticsearch/ResultItem.php index dd8cb62..863e21b 100644 --- a/Classes/Connection/Elasticsearch/ResultItem.php +++ b/Classes/Connection/Elasticsearch/ResultItem.php @@ -44,12 +44,12 @@ class ResultItem implements ResultItemInterface return $this->data[$offset]; } - public function offsetSet() + public function offsetSet($offset, $value) { throw new \BadMethodCallException('It\'s not possible to change the search result.', 1499179077); } - public function offsetUnset() + public function offsetUnset($offset) { throw new \BadMethodCallException('It\'s not possible to change the search result.', 1499179077); } diff --git a/Tests/Functional/Connection/Elasticsearch/FilterTest.php b/Tests/Functional/Connection/Elasticsearch/FilterTest.php index 88ae37f..3492e06 100644 --- a/Tests/Functional/Connection/Elasticsearch/FilterTest.php +++ b/Tests/Functional/Connection/Elasticsearch/FilterTest.php @@ -55,7 +55,7 @@ class FilterTest extends AbstractFunctionalTestCase $searchRequest->setFilter(['CType' => 'html']); $result = $searchService->search($searchRequest); - $this->assertSame('5', $result[0]->getData()['uid'], 'Did not get the expected result entry.'); + $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.'); } } From 38f908711114c8fc550a969c6d31e14943a3ed5c Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Thu, 6 Jul 2017 14:13:39 +0200 Subject: [PATCH 17/20] TASK: Finish interface To stay compatible with implementation. --- Classes/Connection/SearchResultInterface.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Classes/Connection/SearchResultInterface.php b/Classes/Connection/SearchResultInterface.php index a6b2c90..74ac741 100644 --- a/Classes/Connection/SearchResultInterface.php +++ b/Classes/Connection/SearchResultInterface.php @@ -36,4 +36,20 @@ interface SearchResultInterface extends \Iterator, \Countable * @return array */ public function getFacets(); + + /** + * Returns the total sum of matching results. + * + * @return int + */ + public function getTotalCount(); + + // Countable - Interface + + /** + * Returns the total sum of results contained in this result. + * + * @return int + */ + public function count(); } From 3e2e889e277425b01577df6112e0a4e665391296 Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Thu, 6 Jul 2017 15:51:29 +0200 Subject: [PATCH 18/20] TASK: Add tests for new facets Add functional test to test facet configuration including: - Mapping (indexing) - Searching (retrieving of facets) - Filter (already existed, now based on facet case sensitive) --- .../AbstractFunctionalTestCase.php | 3 +- .../Connection/Elasticsearch/FilterTest.php | 35 ++++++++++++++++++- Tests/Functional/Fixtures/BasicSetup.ts | 14 ++++++++ 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/Tests/Functional/Connection/Elasticsearch/AbstractFunctionalTestCase.php b/Tests/Functional/Connection/Elasticsearch/AbstractFunctionalTestCase.php index 363ad6d..1ecdd38 100644 --- a/Tests/Functional/Connection/Elasticsearch/AbstractFunctionalTestCase.php +++ b/Tests/Functional/Connection/Elasticsearch/AbstractFunctionalTestCase.php @@ -44,12 +44,13 @@ abstract class AbstractFunctionalTestCase extends BaseFunctionalTestCase 'port' => getenv('ES_PORT') ?: \Elastica\Connection::DEFAULT_PORT, ]); + // Start with clean system for test. $this->cleanUp(); } public function tearDown() { - // Delete everything so next test starts clean. + // Make system clean again. $this->cleanUp(); } diff --git a/Tests/Functional/Connection/Elasticsearch/FilterTest.php b/Tests/Functional/Connection/Elasticsearch/FilterTest.php index 3492e06..3a0ead8 100644 --- a/Tests/Functional/Connection/Elasticsearch/FilterTest.php +++ b/Tests/Functional/Connection/Elasticsearch/FilterTest.php @@ -53,9 +53,42 @@ class FilterTest extends AbstractFunctionalTestCase $result = $searchService->search($searchRequest); $this->assertSame(2, count($result), 'Did not receive both indexed elements without filter.'); - $searchRequest->setFilter(['CType' => 'html']); + $searchRequest->setFilter(['CType' => 'HTML']); $result = $searchService->search($searchRequest); $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 = $result->getFacets()[0]; + $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[0]; + $this->assertSame('HTML', $option->getName(), 'Option did not have expected Name.'); + $this->assertSame(1, $option->getCount(), 'Option did not have expected count.'); + $option = $options[1]; + $this->assertSame('Header', $option->getName(), 'Option did not have expected Name.'); + $this->assertSame(1, $option->getCount(), 'Option did not have expected count.'); + } } diff --git a/Tests/Functional/Fixtures/BasicSetup.ts b/Tests/Functional/Fixtures/BasicSetup.ts index 72163e3..094fd07 100644 --- a/Tests/Functional/Fixtures/BasicSetup.ts +++ b/Tests/Functional/Fixtures/BasicSetup.ts @@ -11,6 +11,20 @@ plugin { indexing { tt_content { indexer = Leonmrni\SearchCore\Domain\Index\TcaIndexer + + mapping { + CType { + type = keyword + } + } + } + } + + searching { + facets { + contentTypes { + field = CType + } } } } From dfde4b8f6b41f64ed7b5ed20b492ba2c12d46a3f Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Thu, 6 Jul 2017 16:17:30 +0200 Subject: [PATCH 19/20] TASK: Update docs Document new configuration options and adjust configuration where necessary. --- Documentation/source/concepts.rst | 4 +- Documentation/source/configuration.rst | 54 ++++++++++++++++++++++++-- Documentation/source/connections.rst | 4 ++ Documentation/source/development.rst | 9 +++-- Documentation/source/features.rst | 15 +++---- Documentation/source/installation.rst | 7 ++-- Documentation/source/readme.rst | 2 +- Documentation/source/usage.rst | 38 +++++++++++++----- ext_emconf.php | 6 +-- 9 files changed, 103 insertions(+), 36 deletions(-) diff --git a/Documentation/source/concepts.rst b/Documentation/source/concepts.rst index fc0569a..0ce3a0e 100644 --- a/Documentation/source/concepts.rst +++ b/Documentation/source/concepts.rst @@ -24,7 +24,7 @@ Currently only :ref:`Elasticsearch` is provided. Indexing -------- -The indexing is done by one of the available indexer. It should be possible to define the indexer to -use for certain document types. Also it should be possible to write custom indexer to use. +The indexing is done by one of the available indexer. For each identifier it's possible to define +the indexer to use. Also it's possible to write custom indexer to use. Currently only the :ref:`TcaIndexer` is provided. diff --git a/Documentation/source/configuration.rst b/Documentation/source/configuration.rst index 1f16e06..3d8db75 100644 --- a/Documentation/source/configuration.rst +++ b/Documentation/source/configuration.rst @@ -96,8 +96,8 @@ The following settings are available. For each setting its documented which conn .. _configuration_options_index: -index -^^^^^ +Indexing +^^^^^^^^ Holds settings regarding the indexing, e.g. of TYPO3 records, to search services. @@ -108,7 +108,7 @@ Configured as:: settings { indexing { identifier { - indexer = Fully Qualified Classname + indexer = FullyQualifiedClassname // the settings } } @@ -161,3 +161,51 @@ options are available: Make sure to prefix all fields with the corresponding table name. The selection from database will contain joins and can lead to SQL errors if a field exists in multiple tables. + +.. _mapping: + +``mapping`` +""""""""""" + + Used by: Elasticsearch connection while indexing. + + Define mapping for Elasticsearch, have a look at the official docs: https://www.elastic.co/guide/en/elasticsearch/reference/5.2/mapping.html + You are able to define the mapping for each property / columns. + + Example:: + + plugin.tx_searchcore.settings.indexing.tt_content.mapping { + CType { + type = keyword + } + } + + The above example will define the ``CType`` field of ``tt_content`` as ``type: keyword``. This + makes building a facet possible. + + +.. _configuration_options_search: + +Searching +^^^^^^^^^ + +.. _facets: + +``facets`` +""""""""""" + + Used by: Elasticsearch connection while building search query. + + Define aggregations for Elasticsearch, have a look at the official docs: https://www.elastic.co/guide/en/elasticsearch/reference/5.2/search-aggregations-bucket-terms-aggregation.html + Currently only the term facet is provided. + + Example:: + + plugin.tx_searchcore.settings.searching.facets { + contentTypes { + field = CType + } + } + + The above example will provide a facet with options for all found ``CType`` results together + with a count. diff --git a/Documentation/source/connections.rst b/Documentation/source/connections.rst index 678a92d..b51f280 100644 --- a/Documentation/source/connections.rst +++ b/Documentation/source/connections.rst @@ -22,5 +22,9 @@ The connection is configurable through the following options: * :ref:`port` +* :ref:`mapping` + +* :ref:`facets` + .. _elastic Elasticsearch: https://www.elastic.co/products/elasticsearch .. _elastica: http://elastica.io/ diff --git a/Documentation/source/development.rst b/Documentation/source/development.rst index 8026473..e73425c 100644 --- a/Documentation/source/development.rst +++ b/Documentation/source/development.rst @@ -32,9 +32,10 @@ Then setup your system:: git clone git@github.com:DanielSiepmann/search_core.git \ && cd search_core \ - && export typo3DatabaseName="searchcoretest62" \ - && export TYPO3_VERSION="~6.2" \ + && export typo3DatabaseName="searchcoretest76" \ + && export TYPO3_VERSION="~7.6" \ && make install \ + && make unitTests \ && make functionalTests If all tests are okay, start your work. @@ -42,8 +43,8 @@ If all tests are okay, start your work. If you are working with multiple TYPO3 versions make sure to export `typo3DatabaseName` and `TYPO3_VERSION` in your environment like:: - export typo3DatabaseName="searchcoretest76" - export TYPO3_VERSION="~7.6" + export typo3DatabaseName="searchcoretest62" + export TYPO3_VERSION="~6.2" Also run the install command for each version before running any tests. Only this will make sure you are testing against the actual TYPO3 Version and database scheme. diff --git a/Documentation/source/features.rst b/Documentation/source/features.rst index c715512..669e632 100644 --- a/Documentation/source/features.rst +++ b/Documentation/source/features.rst @@ -13,7 +13,7 @@ Indexing Indexing data to Elasticsearch is provided. The extension delivers an indexer for TCA with zero configuration needs. Still it's possible to configure the indexer. -Own indexer are not possible yet, but will. +Also custom classes can be used as indexers. .. _features_search: @@ -24,6 +24,9 @@ Currently all fields are searched for a single search input. Also multiple filter are supported. Filtering results by fields for string contents. +Even facets / aggregates are now possible. Therefore a mapping has to be defined in TypoScript for +indexing, and the facets itself while searching. + .. _features_planned: Planned @@ -31,11 +34,5 @@ Planned The following features are currently planned and will be integrated: -#. Mapping Configuration - Allowing to configure the whole mapping, to define type of input, e.g. integer, keyword. - - -#. Facets / Aggregates - Based on the mapping configuration, facets will be configurable and fetched. Therefore mapping is - required and we will adjust the result set to be of a custom model providing all information in a - more clean way. +#. Pagination + Add a pagination to search results, to allow users to walk through all results. diff --git a/Documentation/source/installation.rst b/Documentation/source/installation.rst index 614b6e6..ddfb065 100644 --- a/Documentation/source/installation.rst +++ b/Documentation/source/installation.rst @@ -6,7 +6,7 @@ Installation The extension can be installed through composer:: - composer require "leonmrni/search_core dev-feature/integrate-elasticsearch" + composer require "leonmrni/search_core dev-master as 1.0.x-dev" or by `downloading`_ and placing it inside the :file:`typo3conf/ext`-Folder of your installation. In that case you need to install all dependencies yourself. Dependencies are: @@ -16,8 +16,7 @@ In that case you need to install all dependencies yourself. Dependencies are: :lines: 19-21 :dedent: 8 - Afterwards you need to enable the extension through the extension manager and include the static -typoscript setup. +TypoScript setup. -.. _downloading: https://github.com/DanielSiepmann/search_core/archive/feature/integrate-elasticsearch.zip +.. _downloading: https://github.com/DanielSiepmann/search_core/archive/master.zip diff --git a/Documentation/source/readme.rst b/Documentation/source/readme.rst index ec5e0e0..95350fa 100644 --- a/Documentation/source/readme.rst +++ b/Documentation/source/readme.rst @@ -18,7 +18,7 @@ reindexing. Current state ------------- -This is still a very early alpha version. More information can be taken from Github at +This is still a very early beta version. More information can be taken from Github at `current issues`_ and `current projects`_. We are also focusing on Code Quality and Testing through `travis ci`_, `scrutinizer`_ and `codacy`_. diff --git a/Documentation/source/usage.rst b/Documentation/source/usage.rst index 453b17d..1ca50d2 100644 --- a/Documentation/source/usage.rst +++ b/Documentation/source/usage.rst @@ -11,12 +11,12 @@ Manual indexing You can trigger indexing from CLI:: - ./typo3/cli_dispatch.phpsh extbase index:index --table 'tt_content' + ./typo3/cli_dispatch.phpsh extbase index:index --identifier 'tt_content' This will index the table ``tt_content`` using the :ref:`TcaIndexer`. -Only one table per call is available, to index multiple tables just make multiple calls. -The tables have to be white listed through :ref:`allowedTables` option. +Only one index per call is available, to run multiple indexers, just make multiple calls. +The indexers have to be defined in TypoScript via :ref:`configuration_options_index`. .. _usage_auto_indexing: @@ -24,7 +24,7 @@ Auto indexing ------------- Indexing is done through hooks every time an record is changed. -The tables have to be white listed through :ref:`allowedTables` option. +The tables have to be configured via :ref:`configuration_options_index`. .. note:: @@ -57,10 +57,28 @@ Filter Thanks to extbase mapping, filter are added to the form: .. code-block:: html - :emphasize-lines: 3 - - - - - + + + +.. _usage_searching_facets: + +Facets +"""""" + +To add a facet as criteria for searching, use :ref:`usage_searching_filter`. + +To display facet results use: + +.. code-block:: html + + + + + + + diff --git a/ext_emconf.php b/ext_emconf.php index 3aab0c7..452a095 100644 --- a/ext_emconf.php +++ b/ext_emconf.php @@ -4,6 +4,7 @@ $EM_CONF[$_EXTKEY] = [ 'title' => 'Search Core', 'description' => 'Search core for implementing various search types.', 'category' => 'be', + 'clearCacheOnLoad' => 1, 'constraints' => [ 'depends' => [ 'typo3' => '7.6.0-7.6.99', @@ -16,9 +17,8 @@ $EM_CONF[$_EXTKEY] = [ 'Leonmrni\\SearchCore\\' => 'Classes', ], ], - 'state' => 'alpha', - 'clearCacheOnLoad' => 1, + 'state' => 'beta', + 'version' => '1.0.0', 'author' => 'Daniel Siepmann', 'author_email' => 'coding@daniel-siepmann.de', - 'version' => '1.0.0', ]; From c58e13cdf67fec8684f06103f1f2d89e381f8d90 Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Thu, 6 Jul 2017 23:48:47 +0200 Subject: [PATCH 20/20] TASK: Rename vendor As we move it from private repo to codappix. --- Classes/Command/IndexCommandController.php | 6 +++--- Classes/Configuration/ConfigurationContainer.php | 2 +- .../ConfigurationContainerInterface.php | 2 +- Classes/Configuration/InvalidArgumentException.php | 2 +- Classes/Configuration/NoConfigurationException.php | 2 +- Classes/Connection/ConnectionInterface.php | 2 +- Classes/Connection/Elasticsearch.php | 6 +++--- Classes/Connection/Elasticsearch/Connection.php | 4 ++-- .../Connection/Elasticsearch/DocumentFactory.php | 2 +- Classes/Connection/Elasticsearch/Facet.php | 6 +++--- Classes/Connection/Elasticsearch/FacetOption.php | 4 ++-- Classes/Connection/Elasticsearch/IndexFactory.php | 2 +- .../Connection/Elasticsearch/MappingFactory.php | 6 +++--- Classes/Connection/Elasticsearch/ResultItem.php | 4 ++-- Classes/Connection/Elasticsearch/SearchResult.php | 8 ++++---- Classes/Connection/Elasticsearch/TypeFactory.php | 2 +- Classes/Connection/FacetInterface.php | 2 +- Classes/Connection/FacetOptionInterface.php | 2 +- Classes/Connection/FacetRequestInterface.php | 2 +- Classes/Connection/ResultItemInterface.php | 2 +- Classes/Connection/SearchRequestInterface.php | 2 +- Classes/Connection/SearchResultInterface.php | 2 +- Classes/Controller/SearchController.php | 6 +++--- Classes/Domain/Index/AbstractIndexer.php | 4 ++-- Classes/Domain/Index/IndexerFactory.php | 12 ++++++------ Classes/Domain/Index/IndexerInterface.php | 2 +- Classes/Domain/Index/IndexingException.php | 2 +- .../Domain/Index/NoMatchingIndexerException.php | 2 +- Classes/Domain/Index/NoRecordFoundException.php | 2 +- Classes/Domain/Index/TcaIndexer.php | 4 ++-- .../Index/TcaIndexer/InvalidArgumentException.php | 2 +- .../Domain/Index/TcaIndexer/RelationResolver.php | 2 +- .../Domain/Index/TcaIndexer/TcaTableService.php | 6 +++--- Classes/Domain/Model/FacetRequest.php | 4 ++-- Classes/Domain/Model/SearchRequest.php | 6 +++--- Classes/Domain/Search/QueryFactory.php | 8 ++++---- Classes/Domain/Search/SearchService.php | 14 +++++++------- Classes/Domain/Service/DataHandler.php | 12 ++++++------ Classes/Hook/DataHandler.php | 8 ++++---- Configuration/TypoScript/setup.txt | 2 +- Documentation/source/conf.py | 8 ++++---- Documentation/source/readme.rst | 10 +++++----- Tests/Functional/AbstractFunctionalTestCase.php | 2 +- .../Elasticsearch/AbstractFunctionalTestCase.php | 4 ++-- .../Connection/Elasticsearch/FilterTest.php | 8 ++++---- .../Connection/Elasticsearch/IndexTcaTableTest.php | 6 +++--- Tests/Functional/Fixtures/BasicSetup.ts | 2 +- .../Hooks/DataHandler/AbstractDataHandlerTest.php | 12 ++++++------ .../DataHandler/IgnoresUnkownOperationTest.php | 8 ++++---- .../Hooks/DataHandler/NonAllowedTablesTest.php | 8 ++++---- ...lowedTablesWithMultipleTablesConfiguredTest.php | 2 +- .../DataHandler/ProcessesAllowedTablesTest.php | 8 ++++---- ...lowedTablesWithMultipleTablesConfiguredTest.php | 2 +- .../Indexing/TcaIndexer/RelationResolverTest.php | 6 +++--- Tests/Functional/Indexing/TcaIndexerTest.php | 14 +++++++------- Tests/Unit/AbstractUnitTestCase.php | 2 +- Tests/Unit/Command/IndexCommandControllerTest.php | 12 ++++++------ .../Index/TcaIndexer/TcaTableServiceTest.php | 8 ++++---- Tests/Unit/Domain/Search/QueryFactoryTest.php | 10 +++++----- composer.json | 10 +++++----- ext_emconf.php | 2 +- ext_localconf.php | 12 ++++++------ ext_tables.php | 2 +- 63 files changed, 164 insertions(+), 164 deletions(-) diff --git a/Classes/Command/IndexCommandController.php b/Classes/Command/IndexCommandController.php index 227918f..b14d4b3 100644 --- a/Classes/Command/IndexCommandController.php +++ b/Classes/Command/IndexCommandController.php @@ -1,5 +1,5 @@ @@ -20,8 +20,8 @@ namespace Leonmrni\SearchCore\Command; * 02110-1301, USA. */ -use Leonmrni\SearchCore\Domain\Index\IndexerFactory; -use Leonmrni\SearchCore\Domain\Index\NoMatchingIndexerException; +use Codappix\SearchCore\Domain\Index\IndexerFactory; +use Codappix\SearchCore\Domain\Index\NoMatchingIndexerException; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Extbase\Mvc\Controller\CommandController; diff --git a/Classes/Configuration/ConfigurationContainer.php b/Classes/Configuration/ConfigurationContainer.php index db66a10..7481692 100644 --- a/Classes/Configuration/ConfigurationContainer.php +++ b/Classes/Configuration/ConfigurationContainer.php @@ -1,5 +1,5 @@ diff --git a/Classes/Configuration/ConfigurationContainerInterface.php b/Classes/Configuration/ConfigurationContainerInterface.php index d0d9828..9429535 100644 --- a/Classes/Configuration/ConfigurationContainerInterface.php +++ b/Classes/Configuration/ConfigurationContainerInterface.php @@ -1,5 +1,5 @@ diff --git a/Classes/Configuration/InvalidArgumentException.php b/Classes/Configuration/InvalidArgumentException.php index fd9e048..1f5f8f0 100644 --- a/Classes/Configuration/InvalidArgumentException.php +++ b/Classes/Configuration/InvalidArgumentException.php @@ -1,5 +1,5 @@ diff --git a/Classes/Configuration/NoConfigurationException.php b/Classes/Configuration/NoConfigurationException.php index bc6c1ba..db4e511 100644 --- a/Classes/Configuration/NoConfigurationException.php +++ b/Classes/Configuration/NoConfigurationException.php @@ -1,5 +1,5 @@ diff --git a/Classes/Connection/ConnectionInterface.php b/Classes/Connection/ConnectionInterface.php index fdd09e3..a130f9e 100644 --- a/Classes/Connection/ConnectionInterface.php +++ b/Classes/Connection/ConnectionInterface.php @@ -1,5 +1,5 @@ diff --git a/Classes/Connection/Elasticsearch.php b/Classes/Connection/Elasticsearch.php index 88b93c2..f6321bc 100644 --- a/Classes/Connection/Elasticsearch.php +++ b/Classes/Connection/Elasticsearch.php @@ -1,5 +1,5 @@ @@ -20,8 +20,8 @@ namespace Leonmrni\SearchCore\Connection; * 02110-1301, USA. */ -use Leonmrni\SearchCore\Connection\Elasticsearch\SearchResult; -use Leonmrni\SearchCore\Domain\Search\QueryFactory; +use Codappix\SearchCore\Connection\Elasticsearch\SearchResult; +use Codappix\SearchCore\Domain\Search\QueryFactory; use TYPO3\CMS\Core\SingletonInterface as Singleton; use TYPO3\CMS\Extbase\Object\ObjectManagerInterface; diff --git a/Classes/Connection/Elasticsearch/Connection.php b/Classes/Connection/Elasticsearch/Connection.php index 25c7361..cd0a1fd 100644 --- a/Classes/Connection/Elasticsearch/Connection.php +++ b/Classes/Connection/Elasticsearch/Connection.php @@ -1,5 +1,5 @@ @@ -20,7 +20,7 @@ namespace Leonmrni\SearchCore\Connection\Elasticsearch; * 02110-1301, USA. */ -use Leonmrni\SearchCore\Configuration\ConfigurationContainerInterface; +use Codappix\SearchCore\Configuration\ConfigurationContainerInterface; use TYPO3\CMS\Core\SingletonInterface as Singleton; /** diff --git a/Classes/Connection/Elasticsearch/DocumentFactory.php b/Classes/Connection/Elasticsearch/DocumentFactory.php index 43462fe..99d29e5 100644 --- a/Classes/Connection/Elasticsearch/DocumentFactory.php +++ b/Classes/Connection/Elasticsearch/DocumentFactory.php @@ -1,5 +1,5 @@ diff --git a/Classes/Connection/Elasticsearch/Facet.php b/Classes/Connection/Elasticsearch/Facet.php index 79a87b3..7893f5f 100644 --- a/Classes/Connection/Elasticsearch/Facet.php +++ b/Classes/Connection/Elasticsearch/Facet.php @@ -1,5 +1,5 @@ @@ -20,8 +20,8 @@ namespace Leonmrni\SearchCore\Connection\Elasticsearch; * 02110-1301, USA. */ -use Leonmrni\SearchCore\Configuration\ConfigurationContainerInterface; -use Leonmrni\SearchCore\Connection\FacetInterface; +use Codappix\SearchCore\Configuration\ConfigurationContainerInterface; +use Codappix\SearchCore\Connection\FacetInterface; class Facet implements FacetInterface { diff --git a/Classes/Connection/Elasticsearch/FacetOption.php b/Classes/Connection/Elasticsearch/FacetOption.php index a618be1..7359434 100644 --- a/Classes/Connection/Elasticsearch/FacetOption.php +++ b/Classes/Connection/Elasticsearch/FacetOption.php @@ -1,5 +1,5 @@ @@ -20,7 +20,7 @@ namespace Leonmrni\SearchCore\Connection\Elasticsearch; * 02110-1301, USA. */ -use Leonmrni\SearchCore\Connection\FacetOptionInterface; +use Codappix\SearchCore\Connection\FacetOptionInterface; class FacetOption implements FacetOptionInterface { diff --git a/Classes/Connection/Elasticsearch/IndexFactory.php b/Classes/Connection/Elasticsearch/IndexFactory.php index 0a06ad4..019b091 100644 --- a/Classes/Connection/Elasticsearch/IndexFactory.php +++ b/Classes/Connection/Elasticsearch/IndexFactory.php @@ -1,5 +1,5 @@ diff --git a/Classes/Connection/Elasticsearch/MappingFactory.php b/Classes/Connection/Elasticsearch/MappingFactory.php index f029cd1..d4ac037 100644 --- a/Classes/Connection/Elasticsearch/MappingFactory.php +++ b/Classes/Connection/Elasticsearch/MappingFactory.php @@ -1,5 +1,5 @@ @@ -20,8 +20,8 @@ namespace Leonmrni\SearchCore\Connection\Elasticsearch; * 02110-1301, USA. */ -use Leonmrni\SearchCore\Configuration\ConfigurationContainerInterface; -use Leonmrni\SearchCore\Configuration\InvalidArgumentException; +use Codappix\SearchCore\Configuration\ConfigurationContainerInterface; +use Codappix\SearchCore\Configuration\InvalidArgumentException; use TYPO3\CMS\Core\SingletonInterface as Singleton; /** diff --git a/Classes/Connection/Elasticsearch/ResultItem.php b/Classes/Connection/Elasticsearch/ResultItem.php index 863e21b..e56783c 100644 --- a/Classes/Connection/Elasticsearch/ResultItem.php +++ b/Classes/Connection/Elasticsearch/ResultItem.php @@ -1,5 +1,5 @@ @@ -20,7 +20,7 @@ namespace Leonmrni\SearchCore\Connection\Elasticsearch; * 02110-1301, USA. */ -use Leonmrni\SearchCore\Connection\ResultItemInterface; +use Codappix\SearchCore\Connection\ResultItemInterface; class ResultItem implements ResultItemInterface { diff --git a/Classes/Connection/Elasticsearch/SearchResult.php b/Classes/Connection/Elasticsearch/SearchResult.php index 63c93b0..f8ffdd8 100644 --- a/Classes/Connection/Elasticsearch/SearchResult.php +++ b/Classes/Connection/Elasticsearch/SearchResult.php @@ -1,5 +1,5 @@ @@ -20,9 +20,9 @@ namespace Leonmrni\SearchCore\Connection\Elasticsearch; * 02110-1301, USA. */ -use Leonmrni\SearchCore\Connection\FacetInterface; -use Leonmrni\SearchCore\Connection\ResultItemInterface; -use Leonmrni\SearchCore\Connection\SearchResultInterface; +use Codappix\SearchCore\Connection\FacetInterface; +use Codappix\SearchCore\Connection\ResultItemInterface; +use Codappix\SearchCore\Connection\SearchResultInterface; use TYPO3\CMS\Extbase\Object\ObjectManagerInterface; class SearchResult implements SearchResultInterface diff --git a/Classes/Connection/Elasticsearch/TypeFactory.php b/Classes/Connection/Elasticsearch/TypeFactory.php index b529937..d5283f8 100644 --- a/Classes/Connection/Elasticsearch/TypeFactory.php +++ b/Classes/Connection/Elasticsearch/TypeFactory.php @@ -1,5 +1,5 @@ diff --git a/Classes/Connection/FacetInterface.php b/Classes/Connection/FacetInterface.php index f422e98..b1cc421 100644 --- a/Classes/Connection/FacetInterface.php +++ b/Classes/Connection/FacetInterface.php @@ -1,5 +1,5 @@ diff --git a/Classes/Connection/FacetOptionInterface.php b/Classes/Connection/FacetOptionInterface.php index b05445b..51a1efd 100644 --- a/Classes/Connection/FacetOptionInterface.php +++ b/Classes/Connection/FacetOptionInterface.php @@ -1,5 +1,5 @@ diff --git a/Classes/Connection/FacetRequestInterface.php b/Classes/Connection/FacetRequestInterface.php index e5a60a1..9352f96 100644 --- a/Classes/Connection/FacetRequestInterface.php +++ b/Classes/Connection/FacetRequestInterface.php @@ -1,5 +1,5 @@ diff --git a/Classes/Connection/ResultItemInterface.php b/Classes/Connection/ResultItemInterface.php index f4c9185..56add2a 100644 --- a/Classes/Connection/ResultItemInterface.php +++ b/Classes/Connection/ResultItemInterface.php @@ -1,5 +1,5 @@ diff --git a/Classes/Connection/SearchRequestInterface.php b/Classes/Connection/SearchRequestInterface.php index 603c02f..ee779f7 100644 --- a/Classes/Connection/SearchRequestInterface.php +++ b/Classes/Connection/SearchRequestInterface.php @@ -1,5 +1,5 @@ diff --git a/Classes/Connection/SearchResultInterface.php b/Classes/Connection/SearchResultInterface.php index 74ac741..5c45bcd 100644 --- a/Classes/Connection/SearchResultInterface.php +++ b/Classes/Connection/SearchResultInterface.php @@ -1,5 +1,5 @@ diff --git a/Classes/Controller/SearchController.php b/Classes/Controller/SearchController.php index b7624f7..068f9a1 100644 --- a/Classes/Controller/SearchController.php +++ b/Classes/Controller/SearchController.php @@ -1,5 +1,5 @@ @@ -20,8 +20,8 @@ namespace Leonmrni\SearchCore\Controller; * 02110-1301, USA. */ -use Leonmrni\SearchCore\Domain\Model\SearchRequest; -use Leonmrni\SearchCore\Domain\Search\SearchService; +use Codappix\SearchCore\Domain\Model\SearchRequest; +use Codappix\SearchCore\Domain\Search\SearchService; use TYPO3\CMS\Extbase\Mvc\Controller\ActionController; /** diff --git a/Classes/Domain/Index/AbstractIndexer.php b/Classes/Domain/Index/AbstractIndexer.php index acd046e..b780dc5 100644 --- a/Classes/Domain/Index/AbstractIndexer.php +++ b/Classes/Domain/Index/AbstractIndexer.php @@ -1,5 +1,5 @@ @@ -20,7 +20,7 @@ namespace Leonmrni\SearchCore\Domain\Index; * 02110-1301, USA. */ -use Leonmrni\SearchCore\Connection\ConnectionInterface; +use Codappix\SearchCore\Connection\ConnectionInterface; abstract class AbstractIndexer implements IndexerInterface { diff --git a/Classes/Domain/Index/IndexerFactory.php b/Classes/Domain/Index/IndexerFactory.php index 24addd1..6618d01 100644 --- a/Classes/Domain/Index/IndexerFactory.php +++ b/Classes/Domain/Index/IndexerFactory.php @@ -1,5 +1,5 @@ @@ -20,11 +20,11 @@ namespace Leonmrni\SearchCore\Domain\Index; * 02110-1301, USA. */ -use Leonmrni\SearchCore\Configuration\ConfigurationContainerInterface; -use Leonmrni\SearchCore\Configuration\InvalidArgumentException; -use Leonmrni\SearchCore\Domain\Index\IndexerInterface; -use Leonmrni\SearchCore\Domain\Index\TcaIndexer; -use Leonmrni\SearchCore\Domain\Index\TcaIndexer\TcaTableService; +use Codappix\SearchCore\Configuration\ConfigurationContainerInterface; +use Codappix\SearchCore\Configuration\InvalidArgumentException; +use Codappix\SearchCore\Domain\Index\IndexerInterface; +use Codappix\SearchCore\Domain\Index\TcaIndexer; +use Codappix\SearchCore\Domain\Index\TcaIndexer\TcaTableService; use TYPO3\CMS\Core\SingletonInterface as Singleton; use TYPO3\CMS\Extbase\Object\ObjectManagerInterface; diff --git a/Classes/Domain/Index/IndexerInterface.php b/Classes/Domain/Index/IndexerInterface.php index d70b410..5fef64f 100644 --- a/Classes/Domain/Index/IndexerInterface.php +++ b/Classes/Domain/Index/IndexerInterface.php @@ -1,5 +1,5 @@ diff --git a/Classes/Domain/Index/IndexingException.php b/Classes/Domain/Index/IndexingException.php index a22660d..d8ca71e 100644 --- a/Classes/Domain/Index/IndexingException.php +++ b/Classes/Domain/Index/IndexingException.php @@ -1,5 +1,5 @@ diff --git a/Classes/Domain/Index/NoMatchingIndexerException.php b/Classes/Domain/Index/NoMatchingIndexerException.php index 02904cc..3f6c094 100644 --- a/Classes/Domain/Index/NoMatchingIndexerException.php +++ b/Classes/Domain/Index/NoMatchingIndexerException.php @@ -1,5 +1,5 @@ diff --git a/Classes/Domain/Index/NoRecordFoundException.php b/Classes/Domain/Index/NoRecordFoundException.php index 8a92408..469359d 100644 --- a/Classes/Domain/Index/NoRecordFoundException.php +++ b/Classes/Domain/Index/NoRecordFoundException.php @@ -1,5 +1,5 @@ diff --git a/Classes/Domain/Index/TcaIndexer.php b/Classes/Domain/Index/TcaIndexer.php index 17dc61e..c29cf60 100644 --- a/Classes/Domain/Index/TcaIndexer.php +++ b/Classes/Domain/Index/TcaIndexer.php @@ -1,5 +1,5 @@ @@ -20,7 +20,7 @@ namespace Leonmrni\SearchCore\Domain\Index; * 02110-1301, USA. */ -use Leonmrni\SearchCore\Connection\ConnectionInterface; +use Codappix\SearchCore\Connection\ConnectionInterface; /** * Will index the given table using configuration from TCA. diff --git a/Classes/Domain/Index/TcaIndexer/InvalidArgumentException.php b/Classes/Domain/Index/TcaIndexer/InvalidArgumentException.php index 0f3dc9a..bc2036f 100644 --- a/Classes/Domain/Index/TcaIndexer/InvalidArgumentException.php +++ b/Classes/Domain/Index/TcaIndexer/InvalidArgumentException.php @@ -1,5 +1,5 @@ diff --git a/Classes/Domain/Index/TcaIndexer/RelationResolver.php b/Classes/Domain/Index/TcaIndexer/RelationResolver.php index 69eb4a2..b09e483 100644 --- a/Classes/Domain/Index/TcaIndexer/RelationResolver.php +++ b/Classes/Domain/Index/TcaIndexer/RelationResolver.php @@ -1,5 +1,5 @@ diff --git a/Classes/Domain/Index/TcaIndexer/TcaTableService.php b/Classes/Domain/Index/TcaIndexer/TcaTableService.php index ae819bc..21e6374 100644 --- a/Classes/Domain/Index/TcaIndexer/TcaTableService.php +++ b/Classes/Domain/Index/TcaIndexer/TcaTableService.php @@ -1,5 +1,5 @@ @@ -20,8 +20,8 @@ namespace Leonmrni\SearchCore\Domain\Index\TcaIndexer; * 02110-1301, USA. */ -use Leonmrni\SearchCore\Configuration\ConfigurationContainerInterface; -use Leonmrni\SearchCore\Domain\Index\IndexingException; +use Codappix\SearchCore\Configuration\ConfigurationContainerInterface; +use Codappix\SearchCore\Domain\Index\IndexingException; use TYPO3\CMS\Backend\Utility\BackendUtility; use TYPO3\CMS\Core\Utility\GeneralUtility; diff --git a/Classes/Domain/Model/FacetRequest.php b/Classes/Domain/Model/FacetRequest.php index 5b8bea6..b1dbc4c 100644 --- a/Classes/Domain/Model/FacetRequest.php +++ b/Classes/Domain/Model/FacetRequest.php @@ -1,5 +1,5 @@ @@ -20,7 +20,7 @@ namespace Leonmrni\SearchCore\Domain\Model; * 02110-1301, USA. */ -use Leonmrni\SearchCore\Connection\FacetRequestInterface; +use Codappix\SearchCore\Connection\FacetRequestInterface; class FacetRequest implements FacetRequestInterface { diff --git a/Classes/Domain/Model/SearchRequest.php b/Classes/Domain/Model/SearchRequest.php index 65ab979..163f65a 100644 --- a/Classes/Domain/Model/SearchRequest.php +++ b/Classes/Domain/Model/SearchRequest.php @@ -1,5 +1,5 @@ @@ -20,8 +20,8 @@ namespace Leonmrni\SearchCore\Domain\Model; * 02110-1301, USA. */ -use Leonmrni\SearchCore\Connection\FacetRequestInterface; -use Leonmrni\SearchCore\Connection\SearchRequestInterface; +use Codappix\SearchCore\Connection\FacetRequestInterface; +use Codappix\SearchCore\Connection\SearchRequestInterface; /** * Represents a search request used to process an actual search. diff --git a/Classes/Domain/Search/QueryFactory.php b/Classes/Domain/Search/QueryFactory.php index 70f42ff..7809fb6 100644 --- a/Classes/Domain/Search/QueryFactory.php +++ b/Classes/Domain/Search/QueryFactory.php @@ -1,5 +1,5 @@ @@ -20,9 +20,9 @@ namespace Leonmrni\SearchCore\Domain\Search; * 02110-1301, USA. */ -use Leonmrni\SearchCore\Connection\ConnectionInterface; -use Leonmrni\SearchCore\Connection\Elasticsearch\Query; -use Leonmrni\SearchCore\Connection\SearchRequestInterface; +use Codappix\SearchCore\Connection\ConnectionInterface; +use Codappix\SearchCore\Connection\Elasticsearch\Query; +use Codappix\SearchCore\Connection\SearchRequestInterface; use TYPO3\CMS\Extbase\Utility\ArrayUtility; class QueryFactory diff --git a/Classes/Domain/Search/SearchService.php b/Classes/Domain/Search/SearchService.php index ac991cd..158d9d1 100644 --- a/Classes/Domain/Search/SearchService.php +++ b/Classes/Domain/Search/SearchService.php @@ -1,5 +1,5 @@ @@ -20,12 +20,12 @@ namespace Leonmrni\SearchCore\Domain\Search; * 02110-1301, USA. */ -use Leonmrni\SearchCore\Configuration\ConfigurationContainerInterface; -use Leonmrni\SearchCore\Configuration\InvalidArgumentException; -use Leonmrni\SearchCore\Connection\ConnectionInterface; -use Leonmrni\SearchCore\Connection\SearchRequestInterface; -use Leonmrni\SearchCore\Connection\SearchResultInterface; -use Leonmrni\SearchCore\Domain\Model\FacetRequest; +use Codappix\SearchCore\Configuration\ConfigurationContainerInterface; +use Codappix\SearchCore\Configuration\InvalidArgumentException; +use Codappix\SearchCore\Connection\ConnectionInterface; +use Codappix\SearchCore\Connection\SearchRequestInterface; +use Codappix\SearchCore\Connection\SearchResultInterface; +use Codappix\SearchCore\Domain\Model\FacetRequest; use TYPO3\CMS\Extbase\Object\ObjectManagerInterface; /** diff --git a/Classes/Domain/Service/DataHandler.php b/Classes/Domain/Service/DataHandler.php index bec9eb3..6ac8069 100644 --- a/Classes/Domain/Service/DataHandler.php +++ b/Classes/Domain/Service/DataHandler.php @@ -1,5 +1,5 @@ @@ -20,10 +20,10 @@ namespace Leonmrni\SearchCore\Domain\Service; * 02110-1301, USA. */ -use Leonmrni\SearchCore\Configuration\ConfigurationContainerInterface; -use Leonmrni\SearchCore\Domain\Index\IndexerFactory; -use Leonmrni\SearchCore\Domain\Index\NoMatchingIndexerException; -use Leonmrni\SearchCore\Domain\Index\TcaIndexer; +use Codappix\SearchCore\Configuration\ConfigurationContainerInterface; +use Codappix\SearchCore\Domain\Index\IndexerFactory; +use Codappix\SearchCore\Domain\Index\NoMatchingIndexerException; +use Codappix\SearchCore\Domain\Index\TcaIndexer; use TYPO3\CMS\Core\SingletonInterface as Singleton; use TYPO3\CMS\Core\Utility\GeneralUtility; @@ -43,7 +43,7 @@ class DataHandler implements Singleton /** * TODO: Only inject on first use?! * - * @var \Leonmrni\SearchCore\Connection\ConnectionInterface + * @var \Codappix\SearchCore\Connection\ConnectionInterface * @inject */ protected $connection; diff --git a/Classes/Hook/DataHandler.php b/Classes/Hook/DataHandler.php index 34cf3f3..d0eb1ba 100644 --- a/Classes/Hook/DataHandler.php +++ b/Classes/Hook/DataHandler.php @@ -1,5 +1,5 @@ @@ -20,9 +20,9 @@ namespace Leonmrni\SearchCore\Hook; * 02110-1301, USA. */ -use Leonmrni\SearchCore\Configuration\NoConfigurationException; -use Leonmrni\SearchCore\Domain\Index\NoMatchingIndexerException; -use Leonmrni\SearchCore\Domain\Service\DataHandler as OwnDataHandler; +use Codappix\SearchCore\Configuration\NoConfigurationException; +use Codappix\SearchCore\Domain\Index\NoMatchingIndexerException; +use Codappix\SearchCore\Domain\Service\DataHandler as OwnDataHandler; use TYPO3\CMS\Backend\Utility\BackendUtility; use TYPO3\CMS\Core\DataHandling\DataHandler as CoreDataHandler; use TYPO3\CMS\Core\Log\LogManager; diff --git a/Configuration/TypoScript/setup.txt b/Configuration/TypoScript/setup.txt index 2d58b35..0efcf4d 100644 --- a/Configuration/TypoScript/setup.txt +++ b/Configuration/TypoScript/setup.txt @@ -10,7 +10,7 @@ plugin { indexing { tt_content { - indexer = Leonmrni\SearchCore\Domain\Index\TcaIndexer + indexer = Codappix\SearchCore\Domain\Index\TcaIndexer additionalWhereClause = {$plugin.tx_searchcore.settings.indexing.tt_content.additionalWhereClause} } } diff --git a/Documentation/source/conf.py b/Documentation/source/conf.py index 07129e7..a708209 100644 --- a/Documentation/source/conf.py +++ b/Documentation/source/conf.py @@ -120,7 +120,7 @@ html_theme = 'alabaster' # documentation. html_theme_options = { 'description': 'TYPO3 Extension to integrate search services.', - 'github_user': 'DanielSiepmann', + 'github_user': 'Codappix', 'github_repo': 'search_core', 'github_button': True, 'github_banner': True, @@ -306,7 +306,7 @@ intersphinx_mapping = { 't3tcaref': ('https://docs.typo3.org/typo3cms/TCAReference/', None), } extlinks = { - 'project': ('https://github.com/DanielSiepmann/search_core/projects/%s', 'Github project: '), - 'pr': ('https://github.com/DanielSiepmann/search_core/pull/%s', 'Github pull request: '), - 'issue': ('https://github.com/DanielSiepmann/search_core/issues/%s', 'Github issue: '), + 'project': ('https://github.com/Codappix/search_core/projects/%s', 'Github project: '), + 'pr': ('https://github.com/Codappix/search_core/pull/%s', 'Github pull request: '), + 'issue': ('https://github.com/Codappix/search_core/issues/%s', 'Github issue: '), } diff --git a/Documentation/source/readme.rst b/Documentation/source/readme.rst index 95350fa..ba77ae8 100644 --- a/Documentation/source/readme.rst +++ b/Documentation/source/readme.rst @@ -23,9 +23,9 @@ This is still a very early beta version. More information can be taken from Gith We are also focusing on Code Quality and Testing through `travis ci`_, `scrutinizer`_ and `codacy`_. -.. _current issues: https://github.com/DanielSiepmann/search_core/issues -.. _current projects: https://github.com/DanielSiepmann/search_core/projects -.. _travis ci: https://travis-ci.org/DanielSiepmann/search_core -.. _scrutinizer: https://scrutinizer-ci.com/g/DanielSiepmann/search_core/inspections -.. _codacy: https://www.codacy.com/app/daniel-siepmann/search_core/dashboard +.. _current issues: https://github.com/Codappix/search_core/issues +.. _current projects: https://github.com/Codappix/search_core/projects +.. _travis ci: https://travis-ci.org/Codappix/search_core +.. _scrutinizer: https://scrutinizer-ci.com/g/Codappix/search_core/inspections +.. _codacy: https://www.codacy.com/app/Codappix/search_core/dashboard diff --git a/Tests/Functional/AbstractFunctionalTestCase.php b/Tests/Functional/AbstractFunctionalTestCase.php index c231784..7f808c7 100644 --- a/Tests/Functional/AbstractFunctionalTestCase.php +++ b/Tests/Functional/AbstractFunctionalTestCase.php @@ -1,5 +1,5 @@ diff --git a/Tests/Functional/Connection/Elasticsearch/AbstractFunctionalTestCase.php b/Tests/Functional/Connection/Elasticsearch/AbstractFunctionalTestCase.php index 1ecdd38..92f9db4 100644 --- a/Tests/Functional/Connection/Elasticsearch/AbstractFunctionalTestCase.php +++ b/Tests/Functional/Connection/Elasticsearch/AbstractFunctionalTestCase.php @@ -1,5 +1,5 @@ @@ -20,7 +20,7 @@ namespace Leonmrni\SearchCore\Tests\Functional\Connection\Elasticsearch; * 02110-1301, USA. */ -use Leonmrni\SearchCore\Tests\Functional\AbstractFunctionalTestCase as BaseFunctionalTestCase; +use Codappix\SearchCore\Tests\Functional\AbstractFunctionalTestCase as BaseFunctionalTestCase; /** * All functional tests should extend this base class. diff --git a/Tests/Functional/Connection/Elasticsearch/FilterTest.php b/Tests/Functional/Connection/Elasticsearch/FilterTest.php index 3a0ead8..aa5a5dc 100644 --- a/Tests/Functional/Connection/Elasticsearch/FilterTest.php +++ b/Tests/Functional/Connection/Elasticsearch/FilterTest.php @@ -1,5 +1,5 @@ @@ -20,9 +20,9 @@ namespace Leonmrni\SearchCore\Tests\Functional\Connection\Elasticsearch; * 02110-1301, USA. */ -use Leonmrni\SearchCore\Domain\Index\IndexerFactory; -use Leonmrni\SearchCore\Domain\Model\SearchRequest; -use Leonmrni\SearchCore\Domain\Search\SearchService; +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 FilterTest extends AbstractFunctionalTestCase diff --git a/Tests/Functional/Connection/Elasticsearch/IndexTcaTableTest.php b/Tests/Functional/Connection/Elasticsearch/IndexTcaTableTest.php index 5e0c1a7..9678d83 100644 --- a/Tests/Functional/Connection/Elasticsearch/IndexTcaTableTest.php +++ b/Tests/Functional/Connection/Elasticsearch/IndexTcaTableTest.php @@ -1,5 +1,5 @@ @@ -20,7 +20,7 @@ namespace Leonmrni\SearchCore\Tests\Functional\Connection\Elasticsearch; * 02110-1301, USA. */ -use Leonmrni\SearchCore\Domain\Index\IndexerFactory; +use Codappix\SearchCore\Domain\Index\IndexerFactory; use TYPO3\CMS\Extbase\Object\ObjectManager; /** @@ -61,7 +61,7 @@ class IndexTcaTableTest extends AbstractFunctionalTestCase /** * @test - * @expectedException \Leonmrni\SearchCore\Domain\Index\IndexingException + * @expectedException \Codappix\SearchCore\Domain\Index\IndexingException */ public function indexingNonConfiguredTableWillThrowException() { diff --git a/Tests/Functional/Fixtures/BasicSetup.ts b/Tests/Functional/Fixtures/BasicSetup.ts index 094fd07..e24aee8 100644 --- a/Tests/Functional/Fixtures/BasicSetup.ts +++ b/Tests/Functional/Fixtures/BasicSetup.ts @@ -10,7 +10,7 @@ plugin { indexing { tt_content { - indexer = Leonmrni\SearchCore\Domain\Index\TcaIndexer + indexer = Codappix\SearchCore\Domain\Index\TcaIndexer mapping { CType { diff --git a/Tests/Functional/Hooks/DataHandler/AbstractDataHandlerTest.php b/Tests/Functional/Hooks/DataHandler/AbstractDataHandlerTest.php index b3c384b..40b64ea 100644 --- a/Tests/Functional/Hooks/DataHandler/AbstractDataHandlerTest.php +++ b/Tests/Functional/Hooks/DataHandler/AbstractDataHandlerTest.php @@ -1,5 +1,5 @@ @@ -20,11 +20,11 @@ namespace Leonmrni\SearchCore\Tests\Functional\Hooks\DataHandler; * 02110-1301, USA. */ -use Leonmrni\SearchCore\Configuration\ConfigurationContainerInterface; -use Leonmrni\SearchCore\Domain\Index\IndexerFactory; -use Leonmrni\SearchCore\Domain\Service\DataHandler as DataHandlerService; -use Leonmrni\SearchCore\Hook\DataHandler as DataHandlerHook; -use Leonmrni\SearchCore\Tests\Functional\AbstractFunctionalTestCase; +use Codappix\SearchCore\Configuration\ConfigurationContainerInterface; +use Codappix\SearchCore\Domain\Index\IndexerFactory; +use Codappix\SearchCore\Domain\Service\DataHandler as DataHandlerService; +use Codappix\SearchCore\Hook\DataHandler as DataHandlerHook; +use Codappix\SearchCore\Tests\Functional\AbstractFunctionalTestCase; use TYPO3\CMS\Core\DataHandling\DataHandler as Typo3DataHandler; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Extbase\Object\ObjectManager; diff --git a/Tests/Functional/Hooks/DataHandler/IgnoresUnkownOperationTest.php b/Tests/Functional/Hooks/DataHandler/IgnoresUnkownOperationTest.php index 44f5186..b1676e3 100644 --- a/Tests/Functional/Hooks/DataHandler/IgnoresUnkownOperationTest.php +++ b/Tests/Functional/Hooks/DataHandler/IgnoresUnkownOperationTest.php @@ -1,5 +1,5 @@ @@ -20,9 +20,9 @@ namespace Leonmrni\SearchCore\Tests\Functional\Hooks\DataHandler; * 02110-1301, USA. */ -use Leonmrni\SearchCore\Configuration\ConfigurationContainerInterface; -use Leonmrni\SearchCore\Domain\Service\DataHandler as DataHandlerService; -use Leonmrni\SearchCore\Hook\DataHandler as DataHandlerHook; +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; diff --git a/Tests/Functional/Hooks/DataHandler/NonAllowedTablesTest.php b/Tests/Functional/Hooks/DataHandler/NonAllowedTablesTest.php index 6073633..c33701d 100644 --- a/Tests/Functional/Hooks/DataHandler/NonAllowedTablesTest.php +++ b/Tests/Functional/Hooks/DataHandler/NonAllowedTablesTest.php @@ -1,5 +1,5 @@ @@ -20,9 +20,9 @@ namespace Leonmrni\SearchCore\Tests\Functional\Hooks\DataHandler; * 02110-1301, USA. */ -use Leonmrni\SearchCore\Configuration\ConfigurationContainerInterface; -use Leonmrni\SearchCore\Domain\Service\DataHandler as DataHandlerService; -use Leonmrni\SearchCore\Hook\DataHandler as DataHandlerHook; +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; diff --git a/Tests/Functional/Hooks/DataHandler/NonAllowedTablesWithMultipleTablesConfiguredTest.php b/Tests/Functional/Hooks/DataHandler/NonAllowedTablesWithMultipleTablesConfiguredTest.php index 0bdf563..ebbee99 100644 --- a/Tests/Functional/Hooks/DataHandler/NonAllowedTablesWithMultipleTablesConfiguredTest.php +++ b/Tests/Functional/Hooks/DataHandler/NonAllowedTablesWithMultipleTablesConfiguredTest.php @@ -1,5 +1,5 @@ diff --git a/Tests/Functional/Hooks/DataHandler/ProcessesAllowedTablesTest.php b/Tests/Functional/Hooks/DataHandler/ProcessesAllowedTablesTest.php index e9e834e..715fe29 100644 --- a/Tests/Functional/Hooks/DataHandler/ProcessesAllowedTablesTest.php +++ b/Tests/Functional/Hooks/DataHandler/ProcessesAllowedTablesTest.php @@ -1,5 +1,5 @@ @@ -20,9 +20,9 @@ namespace Leonmrni\SearchCore\Tests\Functional\Hooks\DataHandler; * 02110-1301, USA. */ -use Leonmrni\SearchCore\Configuration\ConfigurationContainerInterface; -use Leonmrni\SearchCore\Domain\Service\DataHandler as DataHandlerService; -use Leonmrni\SearchCore\Hook\DataHandler as DataHandlerHook; +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; diff --git a/Tests/Functional/Hooks/DataHandler/ProcessesAllowedTablesWithMultipleTablesConfiguredTest.php b/Tests/Functional/Hooks/DataHandler/ProcessesAllowedTablesWithMultipleTablesConfiguredTest.php index f743bdb..c0b0aa3 100644 --- a/Tests/Functional/Hooks/DataHandler/ProcessesAllowedTablesWithMultipleTablesConfiguredTest.php +++ b/Tests/Functional/Hooks/DataHandler/ProcessesAllowedTablesWithMultipleTablesConfiguredTest.php @@ -1,5 +1,5 @@ diff --git a/Tests/Functional/Indexing/TcaIndexer/RelationResolverTest.php b/Tests/Functional/Indexing/TcaIndexer/RelationResolverTest.php index 360cacd..5577ac0 100644 --- a/Tests/Functional/Indexing/TcaIndexer/RelationResolverTest.php +++ b/Tests/Functional/Indexing/TcaIndexer/RelationResolverTest.php @@ -1,5 +1,5 @@ @@ -20,8 +20,8 @@ namespace Leonmrni\SearchCore\Tests\Indexing\TcaIndexer; * 02110-1301, USA. */ -use Leonmrni\SearchCore\Domain\Index\TcaIndexer\TcaTableService; -use Leonmrni\SearchCore\Tests\Functional\AbstractFunctionalTestCase; +use Codappix\SearchCore\Domain\Index\TcaIndexer\TcaTableService; +use Codappix\SearchCore\Tests\Functional\AbstractFunctionalTestCase; use TYPO3\CMS\Backend\Utility\BackendUtility; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Extbase\Object\ObjectManager; diff --git a/Tests/Functional/Indexing/TcaIndexerTest.php b/Tests/Functional/Indexing/TcaIndexerTest.php index 056af39..2b3f817 100644 --- a/Tests/Functional/Indexing/TcaIndexerTest.php +++ b/Tests/Functional/Indexing/TcaIndexerTest.php @@ -1,5 +1,5 @@ @@ -20,12 +20,12 @@ namespace Leonmrni\SearchCore\Tests\Indexing; * 02110-1301, USA. */ -use Leonmrni\SearchCore\Configuration\ConfigurationContainerInterface; -use Leonmrni\SearchCore\Connection\Elasticsearch; -use Leonmrni\SearchCore\Domain\Index\TcaIndexer; -use Leonmrni\SearchCore\Domain\Index\TcaIndexer\RelationResolver; -use Leonmrni\SearchCore\Domain\Index\TcaIndexer\TcaTableService; -use Leonmrni\SearchCore\Tests\Functional\AbstractFunctionalTestCase; +use Codappix\SearchCore\Configuration\ConfigurationContainerInterface; +use Codappix\SearchCore\Connection\Elasticsearch; +use Codappix\SearchCore\Domain\Index\TcaIndexer; +use Codappix\SearchCore\Domain\Index\TcaIndexer\RelationResolver; +use Codappix\SearchCore\Domain\Index\TcaIndexer\TcaTableService; +use Codappix\SearchCore\Tests\Functional\AbstractFunctionalTestCase; use TYPO3\CMS\Extbase\Object\ObjectManager; class TcaIndexerTest extends AbstractFunctionalTestCase diff --git a/Tests/Unit/AbstractUnitTestCase.php b/Tests/Unit/AbstractUnitTestCase.php index 88496a1..c11e74e 100644 --- a/Tests/Unit/AbstractUnitTestCase.php +++ b/Tests/Unit/AbstractUnitTestCase.php @@ -1,5 +1,5 @@ diff --git a/Tests/Unit/Command/IndexCommandControllerTest.php b/Tests/Unit/Command/IndexCommandControllerTest.php index 3dff968..4c81672 100644 --- a/Tests/Unit/Command/IndexCommandControllerTest.php +++ b/Tests/Unit/Command/IndexCommandControllerTest.php @@ -1,5 +1,5 @@ @@ -20,11 +20,11 @@ namespace Leonmrni\SearchCore\Tests\Unit\Command; * 02110-1301, USA. */ -use Leonmrni\SearchCore\Command\IndexCommandController; -use Leonmrni\SearchCore\Domain\Index\IndexerFactory; -use Leonmrni\SearchCore\Domain\Index\NoMatchingIndexerException; -use Leonmrni\SearchCore\Domain\Index\TcaIndexer; -use Leonmrni\SearchCore\Tests\Unit\AbstractUnitTestCase; +use Codappix\SearchCore\Command\IndexCommandController; +use Codappix\SearchCore\Domain\Index\IndexerFactory; +use Codappix\SearchCore\Domain\Index\NoMatchingIndexerException; +use Codappix\SearchCore\Domain\Index\TcaIndexer; +use Codappix\SearchCore\Tests\Unit\AbstractUnitTestCase; use TYPO3\CMS\Extbase\Mvc\Controller\CommandController; use TYPO3\CMS\Extbase\Mvc\Exception\StopActionException; diff --git a/Tests/Unit/Domain/Index/TcaIndexer/TcaTableServiceTest.php b/Tests/Unit/Domain/Index/TcaIndexer/TcaTableServiceTest.php index 837d68c..9e88d4b 100644 --- a/Tests/Unit/Domain/Index/TcaIndexer/TcaTableServiceTest.php +++ b/Tests/Unit/Domain/Index/TcaIndexer/TcaTableServiceTest.php @@ -1,5 +1,5 @@ @@ -20,9 +20,9 @@ namespace Leonmrni\SearchCore\Tests\Unit\Domain\Index\TcaIndexer; * 02110-1301, USA. */ -use Leonmrni\SearchCore\Configuration\ConfigurationContainerInterface; -use Leonmrni\SearchCore\Domain\Index\TcaIndexer\TcaTableService; -use Leonmrni\SearchCore\Tests\Unit\AbstractUnitTestCase; +use Codappix\SearchCore\Configuration\ConfigurationContainerInterface; +use Codappix\SearchCore\Domain\Index\TcaIndexer\TcaTableService; +use Codappix\SearchCore\Tests\Unit\AbstractUnitTestCase; class TcaTableServiceTest extends AbstractUnitTestCase { diff --git a/Tests/Unit/Domain/Search/QueryFactoryTest.php b/Tests/Unit/Domain/Search/QueryFactoryTest.php index 725754f..32c8fbd 100644 --- a/Tests/Unit/Domain/Search/QueryFactoryTest.php +++ b/Tests/Unit/Domain/Search/QueryFactoryTest.php @@ -1,5 +1,5 @@ @@ -20,10 +20,10 @@ namespace Leonmrni\SearchCore\Tests\Unit\Domain\Search; * 02110-1301, USA. */ -use Leonmrni\SearchCore\Domain\Model\FacetRequest; -use Leonmrni\SearchCore\Domain\Model\SearchRequest; -use Leonmrni\SearchCore\Domain\Search\QueryFactory; -use Leonmrni\SearchCore\Tests\Unit\AbstractUnitTestCase; +use Codappix\SearchCore\Domain\Model\FacetRequest; +use Codappix\SearchCore\Domain\Model\SearchRequest; +use Codappix\SearchCore\Domain\Search\QueryFactory; +use Codappix\SearchCore\Tests\Unit\AbstractUnitTestCase; class QueryFactoryTest extends AbstractUnitTestCase { diff --git a/composer.json b/composer.json index debb71f..61aedce 100644 --- a/composer.json +++ b/composer.json @@ -1,17 +1,17 @@ { - "name": "leonmrni/search_core", + "name": "codappix/search_core", "type": "typo3-cms-extension", - "description": "Leonmrni Search Core.", - "homepage": "http://www.leonmrni.com", + "description": "Codappix Search Core.", + "homepage": "https://github.com/Codappix/search_core", "license": ["GPL-2.0+"], "autoload": { "psr-4": { - "Leonmrni\\SearchCore\\": "Classes" + "Codappix\\SearchCore\\": "Classes" } }, "autoload-dev": { "psr-4": { - "Leonmrni\\SearchCore\\Tests\\": "Tests/", + "Codappix\\SearchCore\\Tests\\": "Tests/", "TYPO3\\CMS\\Core\\Tests\\": ".Build/vendor/typo3/cms/typo3/sysext/core/Tests/" } }, diff --git a/ext_emconf.php b/ext_emconf.php index 452a095..118e2df 100644 --- a/ext_emconf.php +++ b/ext_emconf.php @@ -14,7 +14,7 @@ $EM_CONF[$_EXTKEY] = [ ], 'autoload' => [ 'psr-4' => [ - 'Leonmrni\\SearchCore\\' => 'Classes', + 'Codappix\\SearchCore\\' => 'Classes', ], ], 'state' => 'beta', diff --git a/ext_localconf.php b/ext_localconf.php index 7495d73..1c1f9cd 100644 --- a/ext_localconf.php +++ b/ext_localconf.php @@ -11,15 +11,15 @@ call_user_func( 'SC_OPTIONS' => [ 'extbase' => [ 'commandControllers' => [ - Leonmrni\SearchCore\Command\IndexCommandController::class, + Codappix\SearchCore\Command\IndexCommandController::class, ], ], 't3lib/class.t3lib_tcemain.php' => [ 'processCmdmapClass' => [ - $extensionKey => '&' . \Leonmrni\SearchCore\Hook\DataHandler::class, + $extensionKey => '&' . \Codappix\SearchCore\Hook\DataHandler::class, ], 'processDatamapClass' => [ - $extensionKey => '&' . \Leonmrni\SearchCore\Hook\DataHandler::class, + $extensionKey => '&' . \Codappix\SearchCore\Hook\DataHandler::class, ], ], ], @@ -27,7 +27,7 @@ call_user_func( ); TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin( - 'Leonmrni.' . $extensionKey, + 'Codappix.' . $extensionKey, 'search', [ 'Search' => 'search' @@ -39,8 +39,8 @@ call_user_func( \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\CMS\Extbase\Object\Container\Container') ->registerImplementation( - 'Leonmrni\SearchCore\Connection\ConnectionInterface', - 'Leonmrni\SearchCore\Connection\Elasticsearch' + 'Codappix\SearchCore\Connection\ConnectionInterface', + 'Codappix\SearchCore\Connection\Elasticsearch' ); }, $_EXTKEY diff --git a/ext_tables.php b/ext_tables.php index d6d07ed..1a54787 100644 --- a/ext_tables.php +++ b/ext_tables.php @@ -7,7 +7,7 @@ ); TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerPlugin( - 'Leonmrni.' . $_EXTKEY, + 'Codappix.' . $_EXTKEY, 'search', 'Search Core' );