TASK: Move configuration logic into own class

Also add tests for new code.
This commit is contained in:
Daniel Siepmann 2017-10-29 13:44:17 +01:00
parent 85bfb86f5f
commit c38f7b9d6a
Signed by: Daniel Siepmann
GPG key ID: 33D6629915560EF4
5 changed files with 243 additions and 39 deletions

View file

@ -0,0 +1,69 @@
<?php
namespace Codappix\SearchCore\Configuration;
/*
* Copyright (C) 2017 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use Codappix\SearchCore\Connection\SearchRequestInterface;
use TYPO3\CMS\Fluid\View\StandaloneView;
class ConfigurationUtility
{
/**
* Will parse all entries, recursive as fluid template, with request variable set to $searchRequest.
*/
public function replaceArrayValuesWithRequestContent(SearchRequestInterface $searchRequest, array $array) : array
{
array_walk_recursive($array, function (&$value, $key, SearchRequestInterface $searchRequest) {
$template = new StandaloneView();
$template->assign('request', $searchRequest);
$template->setTemplateSource($value);
$value = $template->render();
// As elasticsearch does need some doubles to be send as doubles.
if (is_numeric($value)) {
$value = (float) $value;
}
}, $searchRequest);
return $array;
}
/**
* Will check all entries, whether they have a condition and filter entries out, where condition is false.
* Also will remove condition in the end.
*/
public function filterByCondition(array $entries) : array
{
$entries = array_filter($entries, function ($entry) {
return !is_array($entry)
|| !array_key_exists('condition', $entry)
|| (bool) $entry['condition'] === true
;
});
foreach ($entries as $key => $entry) {
if (is_array($entry) && array_key_exists('condition', $entry)) {
unset($entries[$key]['condition']);
}
}
return $entries;
}
}

View file

@ -21,13 +21,13 @@ namespace Codappix\SearchCore\Domain\Search;
*/ */
use Codappix\SearchCore\Configuration\ConfigurationContainerInterface; use Codappix\SearchCore\Configuration\ConfigurationContainerInterface;
use Codappix\SearchCore\Configuration\ConfigurationUtility;
use Codappix\SearchCore\Configuration\InvalidArgumentException; use Codappix\SearchCore\Configuration\InvalidArgumentException;
use Codappix\SearchCore\Connection\ConnectionInterface; use Codappix\SearchCore\Connection\ConnectionInterface;
use Codappix\SearchCore\Connection\Elasticsearch\Query; use Codappix\SearchCore\Connection\Elasticsearch\Query;
use Codappix\SearchCore\Connection\SearchRequestInterface; use Codappix\SearchCore\Connection\SearchRequestInterface;
use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Utility\ArrayUtility; use TYPO3\CMS\Extbase\Utility\ArrayUtility;
use TYPO3\CMS\Fluid\View\StandaloneView;
class QueryFactory class QueryFactory
{ {
@ -41,12 +41,19 @@ class QueryFactory
*/ */
protected $configuration; protected $configuration;
/**
* @var ConfigurationUtility
*/
protected $configurationUtility;
public function __construct( public function __construct(
\TYPO3\CMS\Core\Log\LogManager $logManager, \TYPO3\CMS\Core\Log\LogManager $logManager,
ConfigurationContainerInterface $configuration ConfigurationContainerInterface $configuration,
ConfigurationUtility $configurationUtility
) { ) {
$this->logger = $logManager->getLogger(__CLASS__); $this->logger = $logManager->getLogger(__CLASS__);
$this->configuration = $configuration; $this->configuration = $configuration;
$this->configurationUtility = $configurationUtility;
} }
/** /**
@ -164,8 +171,8 @@ class QueryFactory
try { try {
$scriptFields = $this->configuration->get('searching.fields.script_fields'); $scriptFields = $this->configuration->get('searching.fields.script_fields');
$scriptFields = $this->replaceArrayValuesWithRequestContent($searchRequest, $scriptFields); $scriptFields = $this->configurationUtility->replaceArrayValuesWithRequestContent($searchRequest, $scriptFields);
$scriptFields = $this->filterByCondition($scriptFields); $scriptFields = $this->configurationUtility->filterByCondition($scriptFields);
if ($scriptFields !== []) { if ($scriptFields !== []) {
$query = ArrayUtility::arrayMergeRecursiveOverrule($query, ['script_fields' => $scriptFields]); $query = ArrayUtility::arrayMergeRecursiveOverrule($query, ['script_fields' => $scriptFields]);
} }
@ -177,8 +184,8 @@ class QueryFactory
protected function addSort(SearchRequestInterface $searchRequest, array &$query) protected function addSort(SearchRequestInterface $searchRequest, array &$query)
{ {
$sorting = $this->configuration->getIfExists('searching.sort') ?: []; $sorting = $this->configuration->getIfExists('searching.sort') ?: [];
$sorting = $this->replaceArrayValuesWithRequestContent($searchRequest, $sorting); $sorting = $this->configurationUtility->replaceArrayValuesWithRequestContent($searchRequest, $sorting);
$sorting = $this->filterByCondition($sorting); $sorting = $this->configurationUtility->filterByCondition($sorting);
if ($sorting !== []) { if ($sorting !== []) {
$query = ArrayUtility::arrayMergeRecursiveOverrule($query, ['sort' => $sorting]); $query = ArrayUtility::arrayMergeRecursiveOverrule($query, ['sort' => $sorting]);
} }
@ -243,36 +250,4 @@ class QueryFactory
]); ]);
} }
} }
protected function replaceArrayValuesWithRequestContent(SearchRequestInterface $searchRequest, array $array) : array
{
array_walk_recursive($array, function (&$value, $key, SearchRequestInterface $searchRequest) {
$template = new StandaloneView();
$template->assign('request', $searchRequest);
$template->setTemplateSource($value);
$value = $template->render();
// As elasticsearch does need some doubles to be end as doubles.
if (is_numeric($value)) {
$value = (float) $value;
}
}, $searchRequest);
return $array;
}
protected function filterByCondition(array $entries) : array
{
$entries = array_filter($entries, function ($entry) {
return !array_key_exists('condition', $entry) || (bool) $entry['condition'] === true;
});
foreach ($entries as $key => $entry) {
if (array_key_exists('condition', $entry)) {
unset($entries[$key]['condition']);
}
}
return $entries;
}
} }

View file

@ -24,6 +24,21 @@ use TYPO3\CMS\Core\Tests\UnitTestCase as CoreTestCase;
abstract class AbstractUnitTestCase extends CoreTestCase abstract class AbstractUnitTestCase extends CoreTestCase
{ {
public function setUp()
{
parent::setUp();
// Disable caching backends to make TYPO3 parts work in unit test mode.
\TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(
\TYPO3\CMS\Core\Cache\CacheManager::class
)->setCacheConfigurations([
'extbase_object' => [
'backend' => \TYPO3\CMS\Core\Cache\Backend\NullBackend::class,
],
]);
}
/** /**
* @return \TYPO3\CMS\Core\Log\LogManager * @return \TYPO3\CMS\Core\Log\LogManager
*/ */

View file

@ -0,0 +1,143 @@
<?php
namespace Codappix\SearchCore\Tests\Unit\Configuration;
/*
* Copyright (C) 2017 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use Codappix\SearchCore\Configuration\ConfigurationUtility;
use Codappix\SearchCore\Connection\SearchRequestInterface;
use Codappix\SearchCore\Domain\Model\SearchRequest;
use Codappix\SearchCore\Tests\Unit\AbstractUnitTestCase;
class ConfigurationUtilityTest extends AbstractUnitTestCase
{
/**
* @test
* @dataProvider possibleRequestAndConfigurationForFluidtemplate
*/
public function recursiveEntriesAreProcessedAsFluidtemplate(SearchRequestInterface $searchRequest, array $array, array $expected)
{
$subject = new ConfigurationUtility();
$this->assertSame(
$expected,
$subject->replaceArrayValuesWithRequestContent($searchRequest, $array),
'Entries in array were not parsed as fluid template with search request.'
);
}
public function possibleRequestAndConfigurationForFluidtemplate() : array
{
return [
'Nothing in array' => [
'searchRequest' => new SearchRequest(),
'array' => [],
'expected' => [],
],
'Small array with nothing to replace' => [
'searchRequest' => new SearchRequest(),
'array' => [
'key1' => 'value1',
],
'expected' => [
'key1' => 'value1',
],
],
'Rescursive array with replacements' => [
'searchRequest' => call_user_func(function () {
$request = new SearchRequest();
$request->setFilter([
'distance' => [
'location' => '10',
],
]);
return $request;
}),
'array' => [
'sub1' => [
'sub1.1' => '{request.filter.distance.location}',
'sub1.2' => '{request.nonExisting}',
],
],
'expected' => [
'sub1' => [
// Numberics are casted to double
'sub1.1' => 10.0,
'sub1.2' => null,
],
],
],
];
}
/**
* @test
* @dataProvider possibleConditionEntries
*/
public function conditionsAreHandledAsExpected(array $entries, array $expected)
{
$subject = new ConfigurationUtility();
$this->assertSame(
$expected,
$subject->filterByCondition($entries),
'Conditions were not processed as expected.'
);
}
public function possibleConditionEntries() : array
{
return [
'Nothing in array' => [
'entries' => [],
'expected' => [],
],
'Entries without condition' => [
'entries' => [
'key1' => 'value1',
],
'expected' => [
'key1' => 'value1',
],
],
'Entry with matching condition' => [
'entries' => [
'sub1' => [
'condition' => true,
'sub1.2' => 'something',
],
],
'expected' => [
'sub1' => [
'sub1.2' => 'something',
],
],
],
'Entry with non matching condition' => [
'entries' => [
'sub1' => [
'condition' => false,
'sub1.2' => 'something',
],
],
'expected' => [],
],
];
}
}

View file

@ -21,6 +21,7 @@ namespace Codappix\SearchCore\Tests\Unit\Domain\Search;
*/ */
use Codappix\SearchCore\Configuration\ConfigurationContainerInterface; use Codappix\SearchCore\Configuration\ConfigurationContainerInterface;
use Codappix\SearchCore\Configuration\ConfigurationUtility;
use Codappix\SearchCore\Configuration\InvalidArgumentException; use Codappix\SearchCore\Configuration\InvalidArgumentException;
use Codappix\SearchCore\Domain\Model\FacetRequest; use Codappix\SearchCore\Domain\Model\FacetRequest;
use Codappix\SearchCore\Domain\Model\SearchRequest; use Codappix\SearchCore\Domain\Model\SearchRequest;
@ -44,7 +45,8 @@ class QueryFactoryTest extends AbstractUnitTestCase
parent::setUp(); parent::setUp();
$this->configuration = $this->getMockBuilder(ConfigurationContainerInterface::class)->getMock(); $this->configuration = $this->getMockBuilder(ConfigurationContainerInterface::class)->getMock();
$this->subject = new QueryFactory($this->getMockedLogger(), $this->configuration); $configurationUtility = new ConfigurationUtility();
$this->subject = new QueryFactory($this->getMockedLogger(), $this->configuration, $configurationUtility);
} }
/** /**