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
+
+
+