mirror of
https://github.com/Codappix/search_core.git
synced 2024-11-23 20:16:10 +01:00
Merge remote-tracking branch 'origin/develop' into support/62
Conflicts: .travis.yml Classes/Domain/Index/TcaIndexer/RelationResolver.php Makefile Tests/Functional/Connection/Elasticsearch/IndexTcaTableTest.php composer.json ext_emconf.php
This commit is contained in:
commit
250dd25107
32 changed files with 872 additions and 163 deletions
|
@ -189,7 +189,7 @@ class Elasticsearch implements Singleton, ConnectionInterface
|
||||||
$search->addIndex('typo3content');
|
$search->addIndex('typo3content');
|
||||||
$search->setQuery($this->queryFactory->create($searchRequest));
|
$search->setQuery($this->queryFactory->create($searchRequest));
|
||||||
|
|
||||||
return $this->objectManager->get(SearchResult::class, $search->search());
|
return $this->objectManager->get(SearchResult::class, $searchRequest, $search->search());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -61,7 +61,10 @@ class DocumentFactory implements Singleton
|
||||||
$identifier = $document['search_identifier'];
|
$identifier = $document['search_identifier'];
|
||||||
unset($document['search_identifier']);
|
unset($document['search_identifier']);
|
||||||
|
|
||||||
$this->logger->debug('Convert document to document', [$identifier, $document]);
|
$this->logger->debug(
|
||||||
|
sprintf('Convert %s %u to document.', $documentType, $identifier),
|
||||||
|
[$identifier, $document]
|
||||||
|
);
|
||||||
return new \Elastica\Document($identifier, $document);
|
return new \Elastica\Document($identifier, $document);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,11 +22,17 @@ namespace Codappix\SearchCore\Connection\Elasticsearch;
|
||||||
|
|
||||||
use Codappix\SearchCore\Connection\FacetInterface;
|
use Codappix\SearchCore\Connection\FacetInterface;
|
||||||
use Codappix\SearchCore\Connection\ResultItemInterface;
|
use Codappix\SearchCore\Connection\ResultItemInterface;
|
||||||
|
use Codappix\SearchCore\Connection\SearchRequestInterface;
|
||||||
use Codappix\SearchCore\Connection\SearchResultInterface;
|
use Codappix\SearchCore\Connection\SearchResultInterface;
|
||||||
use TYPO3\CMS\Extbase\Object\ObjectManagerInterface;
|
use TYPO3\CMS\Extbase\Object\ObjectManagerInterface;
|
||||||
|
|
||||||
class SearchResult implements SearchResultInterface
|
class SearchResult implements SearchResultInterface
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* @var SearchRequestInterface
|
||||||
|
*/
|
||||||
|
protected $searchRequest;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var \Elastica\ResultSet
|
* @var \Elastica\ResultSet
|
||||||
*/
|
*/
|
||||||
|
@ -42,13 +48,24 @@ class SearchResult implements SearchResultInterface
|
||||||
*/
|
*/
|
||||||
protected $results = [];
|
protected $results = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For Iterator interface.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
protected $position = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var ObjectManagerInterface
|
* @var ObjectManagerInterface
|
||||||
*/
|
*/
|
||||||
protected $objectManager;
|
protected $objectManager;
|
||||||
|
|
||||||
public function __construct(\Elastica\ResultSet $result, ObjectManagerInterface $objectManager)
|
public function __construct(
|
||||||
{
|
SearchRequestInterface $searchRequest,
|
||||||
|
\Elastica\ResultSet $result,
|
||||||
|
ObjectManagerInterface $objectManager
|
||||||
|
) {
|
||||||
|
$this->searchRequest = $searchRequest;
|
||||||
$this->result = $result;
|
$this->result = $result;
|
||||||
$this->objectManager = $objectManager;
|
$this->objectManager = $objectManager;
|
||||||
}
|
}
|
||||||
|
@ -75,53 +92,11 @@ class SearchResult implements SearchResultInterface
|
||||||
return $this->facets;
|
return $this->facets;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function getCurrentCount()
|
||||||
* 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();
|
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()
|
protected function initResults()
|
||||||
{
|
{
|
||||||
if ($this->results !== []) {
|
if ($this->results !== []) {
|
||||||
|
@ -143,4 +118,76 @@ class SearchResult implements SearchResultInterface
|
||||||
$this->facets[$aggregationName] = $this->objectManager->get(Facet::class, $aggregationName, $aggregation);
|
$this->facets[$aggregationName] = $this->objectManager->get(Facet::class, $aggregationName, $aggregation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Countable - Interface
|
||||||
|
public function count()
|
||||||
|
{
|
||||||
|
return $this->result->getTotalHits();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterator - Interface
|
||||||
|
public function current()
|
||||||
|
{
|
||||||
|
return $this->getResults()[$this->position];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function next()
|
||||||
|
{
|
||||||
|
++$this->position;
|
||||||
|
|
||||||
|
return $this->current();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function key()
|
||||||
|
{
|
||||||
|
return $this->position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function valid()
|
||||||
|
{
|
||||||
|
return isset($this->getResults()[$this->position]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rewind()
|
||||||
|
{
|
||||||
|
$this->position = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extbase QueryResultInterface - Implemented to support Pagination of Fluid.
|
||||||
|
|
||||||
|
public function getQuery()
|
||||||
|
{
|
||||||
|
return $this->searchRequest;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFirst()
|
||||||
|
{
|
||||||
|
throw new \BadMethodCallException('Method is not implemented yet.', 1502195121);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toArray()
|
||||||
|
{
|
||||||
|
throw new \BadMethodCallException('Method is not implemented yet.', 1502195135);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function offsetExists($offset)
|
||||||
|
{
|
||||||
|
// Return false to allow Fluid to use appropriate getter methods.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function offsetGet($offset)
|
||||||
|
{
|
||||||
|
throw new \BadMethodCallException('Use getter to fetch properties.', 1502196933);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function offsetSet($offset, $value)
|
||||||
|
{
|
||||||
|
throw new \BadMethodCallException('You are not allowed to modify the result.', 1502196934);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function offsetUnset($offset)
|
||||||
|
{
|
||||||
|
throw new \BadMethodCallException('You are not allowed to modify the result.', 1502196936);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,10 +20,9 @@ namespace Codappix\SearchCore\Connection;
|
||||||
* 02110-1301, USA.
|
* 02110-1301, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
use TYPO3\CMS\Extbase\Persistence\QueryInterface;
|
||||||
*
|
|
||||||
*/
|
interface SearchRequestInterface extends QueryInterface
|
||||||
interface SearchRequestInterface
|
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Returns the actual string the user searched for.
|
* Returns the actual string the user searched for.
|
||||||
|
@ -41,11 +40,4 @@ interface SearchRequestInterface
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function getFilter();
|
public function getFilter();
|
||||||
|
|
||||||
/**
|
|
||||||
* Defines how many results should be fetched.
|
|
||||||
*
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
public function getSize();
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,10 +20,12 @@ namespace Codappix\SearchCore\Connection;
|
||||||
* 02110-1301, USA.
|
* 02110-1301, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use TYPO3\CMS\Extbase\Persistence\QueryResultInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A search result.
|
* A search result.
|
||||||
*/
|
*/
|
||||||
interface SearchResultInterface extends \Iterator, \Countable
|
interface SearchResultInterface extends \Iterator, \Countable, QueryResultInterface
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @return array<ResultItemInterface>
|
* @return array<ResultItemInterface>
|
||||||
|
@ -38,18 +40,9 @@ interface SearchResultInterface extends \Iterator, \Countable
|
||||||
public function getFacets();
|
public function getFacets();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the total sum of matching results.
|
* Returns the number of results in current result
|
||||||
*
|
*
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function getTotalCount();
|
public function getCurrentCount();
|
||||||
|
|
||||||
// Countable - Interface
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the total sum of results contained in this result.
|
|
||||||
*
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
public function count();
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,20 @@ class SearchController extends ActionController
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function initializeSearchAction()
|
||||||
|
{
|
||||||
|
if (isset($this->settings['searching']['mode']) && $this->settings['searching']['mode'] === 'filter'
|
||||||
|
&& $this->request->hasArgument('searchRequest') === false
|
||||||
|
) {
|
||||||
|
$this->request->setArguments(array_merge(
|
||||||
|
$this->request->getArguments(),
|
||||||
|
[
|
||||||
|
'searchRequest' => $this->objectManager->get(SearchRequest::class),
|
||||||
|
]
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process a search and deliver original request and result to view.
|
* Process a search and deliver original request and result to view.
|
||||||
*
|
*
|
||||||
|
|
|
@ -24,6 +24,8 @@ use Codappix\SearchCore\Configuration\ConfigurationContainerInterface;
|
||||||
use Codappix\SearchCore\Domain\Index\IndexingException;
|
use Codappix\SearchCore\Domain\Index\IndexingException;
|
||||||
use TYPO3\CMS\Backend\Utility\BackendUtility;
|
use TYPO3\CMS\Backend\Utility\BackendUtility;
|
||||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||||
|
use TYPO3\CMS\Core\Utility\RootlineUtility;
|
||||||
|
use TYPO3\CMS\Extbase\Object\ObjectManagerInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encapsulate logik related to TCA configuration.
|
* Encapsulate logik related to TCA configuration.
|
||||||
|
@ -47,15 +49,20 @@ class TcaTableService
|
||||||
*/
|
*/
|
||||||
protected $configuration;
|
protected $configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var RelationResolver
|
||||||
|
*/
|
||||||
|
protected $relationResolver;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var \TYPO3\CMS\Core\Log\Logger
|
* @var \TYPO3\CMS\Core\Log\Logger
|
||||||
*/
|
*/
|
||||||
protected $logger;
|
protected $logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var RelationResolver
|
* @var ObjectManagerInterface
|
||||||
*/
|
*/
|
||||||
protected $relationResolver;
|
protected $objectManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inject log manager to get concrete logger from it.
|
* Inject log manager to get concrete logger from it.
|
||||||
|
@ -67,6 +74,14 @@ class TcaTableService
|
||||||
$this->logger = $logManager->getLogger(__CLASS__);
|
$this->logger = $logManager->getLogger(__CLASS__);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ObjectManagerInterface $objectManager
|
||||||
|
*/
|
||||||
|
public function injectObjectManager(ObjectManagerInterface $objectManager)
|
||||||
|
{
|
||||||
|
$this->objectManager = $objectManager;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $tableName
|
* @param string $tableName
|
||||||
* @param ConfigurationContainerInterface $configuration
|
* @param ConfigurationContainerInterface $configuration
|
||||||
|
@ -243,26 +258,59 @@ class TcaTableService
|
||||||
* Checks whether the given record was blacklisted by root line.
|
* Checks whether the given record was blacklisted by root line.
|
||||||
* This can be configured by typoscript as whole root lines can be black listed.
|
* This can be configured by typoscript as whole root lines can be black listed.
|
||||||
*
|
*
|
||||||
* NOTE: Does not support pages yet. We have to add a switch once we
|
* Also further TYPO3 mechanics are taken into account. Does a valid root
|
||||||
* support them to use uid instead.
|
* line exist, is page inside a recycler, is inherited start- endtime
|
||||||
|
* excluded, etc.
|
||||||
*
|
*
|
||||||
* @param array &$record
|
* @param array &$record
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
protected function isRecordBlacklistedByRootline(array &$record)
|
protected function isRecordBlacklistedByRootline(array &$record)
|
||||||
{
|
{
|
||||||
// If no rootline exists, the record is on a unreachable page and therefore blacklisted.
|
$pageUid = $record['pid'];
|
||||||
$rootline = BackendUtility::BEgetRootLine($record['pid']);
|
if ($this->tableName === 'pages') {
|
||||||
if (!isset($rootline[0])) {
|
$pageUid = $record['uid'];
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$rootline = $this->objectManager->get(RootlineUtility::class, $pageUid)->get();
|
||||||
|
} catch (\RuntimeException $e) {
|
||||||
|
$this->logger->notice(
|
||||||
|
sprintf('Could not fetch rootline for page %u, because: %s', $pageUid, $e->getMessage()),
|
||||||
|
[$record, $e]
|
||||||
|
);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check configured black list if present.
|
|
||||||
if ($this->isBlackListedRootLineConfigured()) {
|
|
||||||
foreach ($rootline as $pageInRootLine) {
|
foreach ($rootline as $pageInRootLine) {
|
||||||
if (in_array($pageInRootLine['uid'], $this->getBlackListedRootLine())) {
|
// Check configured black list if present.
|
||||||
|
if ($this->isBlackListedRootLineConfigured()
|
||||||
|
&& in_array($pageInRootLine['uid'], $this->getBlackListedRootLine())
|
||||||
|
) {
|
||||||
|
$this->logger->info(
|
||||||
|
sprintf(
|
||||||
|
'Record %u is black listed due to configured root line configuration of page %u.',
|
||||||
|
$record['uid'],
|
||||||
|
$pageInRootLine['uid']
|
||||||
|
),
|
||||||
|
[$record, $pageInRootLine]
|
||||||
|
);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($pageInRootLine['extendToSubpages'] && (
|
||||||
|
($pageInRootLine['endtime'] > 0 && $pageInRootLine['endtime'] <= time())
|
||||||
|
|| ($pageInRootLine['starttime'] > 0 && $pageInRootLine['starttime'] >= time())
|
||||||
|
)) {
|
||||||
|
$this->logger->info(
|
||||||
|
sprintf(
|
||||||
|
'Record %u is black listed due to configured timing of parent page %u.',
|
||||||
|
$record['uid'],
|
||||||
|
$pageInRootLine['uid']
|
||||||
|
),
|
||||||
|
[$record, $pageInRootLine]
|
||||||
|
);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ namespace Codappix\SearchCore\Domain\Model;
|
||||||
* 02110-1301, USA.
|
* 02110-1301, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use Codappix\SearchCore\Connection\ConnectionInterface;
|
||||||
use Codappix\SearchCore\Connection\FacetRequestInterface;
|
use Codappix\SearchCore\Connection\FacetRequestInterface;
|
||||||
use Codappix\SearchCore\Connection\SearchRequestInterface;
|
use Codappix\SearchCore\Connection\SearchRequestInterface;
|
||||||
|
|
||||||
|
@ -35,11 +36,6 @@ class SearchRequest implements SearchRequestInterface
|
||||||
*/
|
*/
|
||||||
protected $query = '';
|
protected $query = '';
|
||||||
|
|
||||||
/**
|
|
||||||
* @var int
|
|
||||||
*/
|
|
||||||
protected $size = 10;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
|
@ -50,10 +46,27 @@ class SearchRequest implements SearchRequestInterface
|
||||||
*/
|
*/
|
||||||
protected $facets = [];
|
protected $facets = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
protected $offset = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
protected $limit = 10;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used for QueryInterface implementation to allow execute method to work.
|
||||||
|
*
|
||||||
|
* @var ConnectionInterface
|
||||||
|
*/
|
||||||
|
protected $connection = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $query
|
* @param string $query
|
||||||
*/
|
*/
|
||||||
public function __construct($query)
|
public function __construct($query = '')
|
||||||
{
|
{
|
||||||
$this->query = (string) $query;
|
$this->query = (string) $query;
|
||||||
}
|
}
|
||||||
|
@ -119,18 +132,162 @@ class SearchRequest implements SearchRequestInterface
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return int
|
* Define connection to use for this request.
|
||||||
|
* Necessary to allow implementation of execute for interface.
|
||||||
|
*
|
||||||
|
* @param ConnectionInterface $connection
|
||||||
*/
|
*/
|
||||||
public function getSize()
|
public function setConnection(ConnectionInterface $connection)
|
||||||
{
|
{
|
||||||
return $this->size;
|
$this->connection = $connection;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// Extbase QueryInterface
|
||||||
* @param int $size
|
// Current implementation covers only paginate widget support.
|
||||||
*/
|
public function execute($returnRawQueryResult = false)
|
||||||
public function setSize($size)
|
|
||||||
{
|
{
|
||||||
$this->size = (int) $size;
|
if ($this->connection instanceof ConnectionInterface) {
|
||||||
|
return $this->connection->search($this);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \InvalidArgumentException(
|
||||||
|
'Connection was not set before, therefore execute can not work. Use `setConnection` before.',
|
||||||
|
1502197732
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setLimit($limit)
|
||||||
|
{
|
||||||
|
$this->limit = (int) $limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setOffset($offset)
|
||||||
|
{
|
||||||
|
$this->offset = (int) $offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLimit()
|
||||||
|
{
|
||||||
|
return $this->limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getOffset()
|
||||||
|
{
|
||||||
|
return $this->offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSource()
|
||||||
|
{
|
||||||
|
throw new \BadMethodCallException('Method is not implemented yet.', 1502196146);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setOrderings(array $orderings)
|
||||||
|
{
|
||||||
|
throw new \BadMethodCallException('Method is not implemented yet.', 1502196163);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function matching($constraint)
|
||||||
|
{
|
||||||
|
throw new \BadMethodCallException('Method is not implemented yet.', 1502196197);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function logicalAnd($constraint1)
|
||||||
|
{
|
||||||
|
throw new \BadMethodCallException('Method is not implemented yet.', 1502196166);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function logicalOr($constraint1)
|
||||||
|
{
|
||||||
|
throw new \BadMethodCallException('Method is not implemented yet.', 1502196198);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function logicalNot(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\ConstraintInterface $constraint)
|
||||||
|
{
|
||||||
|
throw new \BadMethodCallException('Method is not implemented yet.', 1502196166);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function equals($propertyName, $operand, $caseSensitive = true)
|
||||||
|
{
|
||||||
|
throw new \BadMethodCallException('Method is not implemented yet.', 1502196199);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function like($propertyName, $operand, $caseSensitive = true)
|
||||||
|
{
|
||||||
|
throw new \BadMethodCallException('Method is not implemented yet.', 1502196167);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function contains($propertyName, $operand)
|
||||||
|
{
|
||||||
|
throw new \BadMethodCallException('Method is not implemented yet.', 1502196200);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function in($propertyName, $operand)
|
||||||
|
{
|
||||||
|
throw new \BadMethodCallException('Method is not implemented yet.', 1502196167);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function lessThan($propertyName, $operand)
|
||||||
|
{
|
||||||
|
throw new \BadMethodCallException('Method is not implemented yet.', 1502196201);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function lessThanOrEqual($propertyName, $operand)
|
||||||
|
{
|
||||||
|
throw new \BadMethodCallException('Method is not implemented yet.', 1502196168);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function greaterThan($propertyName, $operand)
|
||||||
|
{
|
||||||
|
throw new \BadMethodCallException('Method is not implemented yet.', 1502196202);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function greaterThanOrEqual($propertyName, $operand)
|
||||||
|
{
|
||||||
|
throw new \BadMethodCallException('Method is not implemented yet.', 1502196168);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getType()
|
||||||
|
{
|
||||||
|
throw new \BadMethodCallException('Method is not implemented yet.', 1502196203);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setQuerySettings(\TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface $querySettings)
|
||||||
|
{
|
||||||
|
throw new \BadMethodCallException('Method is not implemented yet.', 1502196168);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getQuerySettings()
|
||||||
|
{
|
||||||
|
throw new \BadMethodCallException('Method is not implemented yet.', 1502196205);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function count()
|
||||||
|
{
|
||||||
|
throw new \BadMethodCallException('Method is not implemented yet.', 1502196169);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getOrderings()
|
||||||
|
{
|
||||||
|
throw new \BadMethodCallException('Method is not implemented yet.', 1502196206);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getConstraint()
|
||||||
|
{
|
||||||
|
throw new \BadMethodCallException('Method is not implemented yet.', 1502196171);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isEmpty($propertyName)
|
||||||
|
{
|
||||||
|
throw new \BadMethodCallException('Method is not implemented yet.', 1502196207);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setSource(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\SourceInterface $source)
|
||||||
|
{
|
||||||
|
throw new \BadMethodCallException('Method is not implemented yet.', 1502196172);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getStatement()
|
||||||
|
{
|
||||||
|
throw new \BadMethodCallException('Method is not implemented yet.', 1502196208);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,11 +39,6 @@ class QueryFactory
|
||||||
*/
|
*/
|
||||||
protected $configuration;
|
protected $configuration;
|
||||||
|
|
||||||
/**
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
protected $query = [];
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param \TYPO3\CMS\Core\Log\LogManager $logManager
|
* @param \TYPO3\CMS\Core\Log\LogManager $logManager
|
||||||
* @param ConfigurationContainerInterface $configuration
|
* @param ConfigurationContainerInterface $configuration
|
||||||
|
@ -77,46 +72,53 @@ class QueryFactory
|
||||||
*/
|
*/
|
||||||
protected function createElasticaQuery(SearchRequestInterface $searchRequest)
|
protected function createElasticaQuery(SearchRequestInterface $searchRequest)
|
||||||
{
|
{
|
||||||
$this->addSize($searchRequest);
|
$query = [];
|
||||||
$this->addSearch($searchRequest);
|
$this->addSize($searchRequest, $query);
|
||||||
$this->addBoosts($searchRequest);
|
$this->addSearch($searchRequest, $query);
|
||||||
$this->addFilter($searchRequest);
|
$this->addBoosts($searchRequest, $query);
|
||||||
$this->addFacets($searchRequest);
|
$this->addFilter($searchRequest, $query);
|
||||||
|
$this->addFacets($searchRequest, $query);
|
||||||
|
|
||||||
// Use last, as it might change structure of query.
|
// Use last, as it might change structure of query.
|
||||||
// Better approach would be something like DQL to generate query and build result in the end.
|
// Better approach would be something like DQL to generate query and build result in the end.
|
||||||
$this->addFactorBoost();
|
$this->addFactorBoost($query);
|
||||||
|
|
||||||
$this->logger->debug('Generated elasticsearch query.', [$this->query]);
|
$this->logger->debug('Generated elasticsearch query.', [$query]);
|
||||||
return new \Elastica\Query($this->query);
|
return new \Elastica\Query($query);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param SearchRequestInterface $searchRequest
|
* @param SearchRequestInterface $searchRequest
|
||||||
|
* @param array $query
|
||||||
*/
|
*/
|
||||||
protected function addSize(SearchRequestInterface $searchRequest)
|
protected function addSize(SearchRequestInterface $searchRequest, array &$query)
|
||||||
{
|
{
|
||||||
$this->query = ArrayUtility::arrayMergeRecursiveOverrule($this->query, [
|
$query = ArrayUtility::arrayMergeRecursiveOverrule($query, [
|
||||||
'from' => 0,
|
'from' => $searchRequest->getOffset(),
|
||||||
'size' => $searchRequest->getSize(),
|
'size' => $searchRequest->getLimit(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param SearchRequestInterface $searchRequest
|
* @param SearchRequestInterface $searchRequest
|
||||||
|
* @param array $query
|
||||||
*/
|
*/
|
||||||
protected function addSearch(SearchRequestInterface $searchRequest)
|
protected function addSearch(SearchRequestInterface $searchRequest, array &$query)
|
||||||
{
|
{
|
||||||
$this->query = ArrayUtility::setValueByPath(
|
if (trim($searchRequest->getSearchTerm()) === '') {
|
||||||
$this->query,
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$query = ArrayUtility::setValueByPath(
|
||||||
|
$query,
|
||||||
'query.bool.must.0.match._all.query',
|
'query.bool.must.0.match._all.query',
|
||||||
$searchRequest->getSearchTerm()
|
$searchRequest->getSearchTerm()
|
||||||
);
|
);
|
||||||
|
|
||||||
$minimumShouldMatch = $this->configuration->getIfExists('searching.minimumShouldMatch');
|
$minimumShouldMatch = $this->configuration->getIfExists('searching.minimumShouldMatch');
|
||||||
if ($minimumShouldMatch) {
|
if ($minimumShouldMatch) {
|
||||||
$this->query = ArrayUtility::setValueByPath(
|
$query = ArrayUtility::setValueByPath(
|
||||||
$this->query,
|
$query,
|
||||||
'query.bool.must.0.match._all.minimum_should_match',
|
'query.bool.must.0.match._all.minimum_should_match',
|
||||||
$minimumShouldMatch
|
$minimumShouldMatch
|
||||||
);
|
);
|
||||||
|
@ -125,8 +127,9 @@ class QueryFactory
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param SearchRequestInterface $searchRequest
|
* @param SearchRequestInterface $searchRequest
|
||||||
|
* @param array $query
|
||||||
*/
|
*/
|
||||||
protected function addBoosts(SearchRequestInterface $searchRequest)
|
protected function addBoosts(SearchRequestInterface $searchRequest, array &$query)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$fields = $this->configuration->get('searching.boost');
|
$fields = $this->configuration->get('searching.boost');
|
||||||
|
@ -147,7 +150,7 @@ class QueryFactory
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->query = ArrayUtility::arrayMergeRecursiveOverrule($this->query, [
|
$query = ArrayUtility::arrayMergeRecursiveOverrule($query, [
|
||||||
'query' => [
|
'query' => [
|
||||||
'bool' => [
|
'bool' => [
|
||||||
'should' => $boostQueryParts,
|
'should' => $boostQueryParts,
|
||||||
|
@ -156,12 +159,15 @@ class QueryFactory
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function addFactorBoost()
|
/**
|
||||||
|
* @param array $query
|
||||||
|
*/
|
||||||
|
protected function addFactorBoost(array &$query)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$this->query['query'] = [
|
$query['query'] = [
|
||||||
'function_score' => [
|
'function_score' => [
|
||||||
'query' => $this->query['query'],
|
'query' => $query['query'],
|
||||||
'field_value_factor' => $this->configuration->get('searching.fieldValueFactor'),
|
'field_value_factor' => $this->configuration->get('searching.fieldValueFactor'),
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
@ -172,8 +178,9 @@ class QueryFactory
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param SearchRequestInterface $searchRequest
|
* @param SearchRequestInterface $searchRequest
|
||||||
|
* @param array $query
|
||||||
*/
|
*/
|
||||||
protected function addFilter(SearchRequestInterface $searchRequest)
|
protected function addFilter(SearchRequestInterface $searchRequest, array &$query)
|
||||||
{
|
{
|
||||||
if (! $searchRequest->hasFilter()) {
|
if (! $searchRequest->hasFilter()) {
|
||||||
return;
|
return;
|
||||||
|
@ -188,7 +195,7 @@ class QueryFactory
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->query = ArrayUtility::arrayMergeRecursiveOverrule($this->query, [
|
$query = ArrayUtility::arrayMergeRecursiveOverrule($query, [
|
||||||
'query' => [
|
'query' => [
|
||||||
'bool' => [
|
'bool' => [
|
||||||
'filter' => $terms,
|
'filter' => $terms,
|
||||||
|
@ -199,11 +206,12 @@ class QueryFactory
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param SearchRequestInterface $searchRequest
|
* @param SearchRequestInterface $searchRequest
|
||||||
|
* @param array $query
|
||||||
*/
|
*/
|
||||||
protected function addFacets(SearchRequestInterface $searchRequest)
|
protected function addFacets(SearchRequestInterface $searchRequest, array &$query)
|
||||||
{
|
{
|
||||||
foreach ($searchRequest->getFacets() as $facet) {
|
foreach ($searchRequest->getFacets() as $facet) {
|
||||||
$this->query = ArrayUtility::arrayMergeRecursiveOverrule($this->query, [
|
$query = ArrayUtility::arrayMergeRecursiveOverrule($query, [
|
||||||
'aggs' => [
|
'aggs' => [
|
||||||
$facet->getIdentifier() => [
|
$facet->getIdentifier() => [
|
||||||
'terms' => [
|
'terms' => [
|
||||||
|
|
|
@ -69,8 +69,10 @@ class SearchService
|
||||||
*/
|
*/
|
||||||
public function search(SearchRequestInterface $searchRequest)
|
public function search(SearchRequestInterface $searchRequest)
|
||||||
{
|
{
|
||||||
|
$searchRequest->setConnection($this->connection);
|
||||||
$this->addSize($searchRequest);
|
$this->addSize($searchRequest);
|
||||||
$this->addConfiguredFacets($searchRequest);
|
$this->addConfiguredFacets($searchRequest);
|
||||||
|
$this->addConfiguredFilters($searchRequest);
|
||||||
|
|
||||||
return $this->connection->search($searchRequest);
|
return $this->connection->search($searchRequest);
|
||||||
}
|
}
|
||||||
|
@ -82,7 +84,7 @@ class SearchService
|
||||||
*/
|
*/
|
||||||
protected function addSize(SearchRequestInterface $searchRequest)
|
protected function addSize(SearchRequestInterface $searchRequest)
|
||||||
{
|
{
|
||||||
$searchRequest->setSize(
|
$searchRequest->setLimit(
|
||||||
$this->configuration->getIfExists('searching.size') ?: 10
|
$this->configuration->getIfExists('searching.size') ?: 10
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -112,4 +114,21 @@ class SearchService
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add filters from configuration, e.g. flexform or TypoScript.
|
||||||
|
*
|
||||||
|
* @param SearchRequestInterface $searchRequest
|
||||||
|
*/
|
||||||
|
protected function addConfiguredFilters(SearchRequestInterface $searchRequest)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$searchRequest->setFilter(array_merge(
|
||||||
|
$searchRequest->getFilter(),
|
||||||
|
$this->configuration->get('searching.filter')
|
||||||
|
));
|
||||||
|
} catch (InvalidArgumentException $e) {
|
||||||
|
// Nothing todo, no filter configured.
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
3
Configuration/TCA/Overrides/tt_content.php
Normal file
3
Configuration/TCA/Overrides/tt_content.php
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
$GLOBALS['TCA']['tt_content']['types']['list']['subtypes_excludelist']['searchcore_search'] = 'recursive,pages';
|
|
@ -9,6 +9,10 @@ plugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
indexing {
|
indexing {
|
||||||
|
tt_content {
|
||||||
|
additionalWhereClause = tt_content.CType NOT IN ('gridelements_pi1', 'list', 'div', 'menu', 'shortcut', 'search', 'login') AND tt_content.bodytext != ''
|
||||||
|
}
|
||||||
|
|
||||||
pages {
|
pages {
|
||||||
additionalWhereClause = pages.doktype NOT IN (3, 199, 6, 254, 255)
|
additionalWhereClause = pages.doktype NOT IN (3, 199, 6, 254, 255)
|
||||||
abstractFields = abstract, description, bodytext
|
abstractFields = abstract, description, bodytext
|
||||||
|
|
|
@ -12,10 +12,7 @@ plugin {
|
||||||
# Not for direct indexing therefore no indexer.
|
# Not for direct indexing therefore no indexer.
|
||||||
# Used to configure tt_content fetching while indexing pages
|
# Used to configure tt_content fetching while indexing pages
|
||||||
tt_content {
|
tt_content {
|
||||||
additionalWhereClause (
|
additionalWhereClause = {$plugin.tx_searchcore.settings.indexing.tt_content.additionalWhereClause}
|
||||||
tt_content.CType NOT IN ('gridelements_pi1', 'list', 'div', 'menu', 'shortcut', 'search', 'login')
|
|
||||||
AND tt_content.bodytext != ''
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pages {
|
pages {
|
||||||
|
|
|
@ -279,6 +279,23 @@ Searching
|
||||||
The above example will provide a facet with options for all found ``CType`` results together
|
The above example will provide a facet with options for all found ``CType`` results together
|
||||||
with a count.
|
with a count.
|
||||||
|
|
||||||
|
.. _filter:
|
||||||
|
|
||||||
|
``filter``
|
||||||
|
"""""""""""
|
||||||
|
|
||||||
|
Used by: While building search request.
|
||||||
|
|
||||||
|
Define filter that should be set for all requests.
|
||||||
|
|
||||||
|
Example::
|
||||||
|
|
||||||
|
plugin.tx_searchcore.settings.searching.filter {
|
||||||
|
property = value
|
||||||
|
}
|
||||||
|
|
||||||
|
For Elasticsearch the fields have to be filterable, e.g. need a mapping as ``keyword``.
|
||||||
|
|
||||||
.. _minimumShouldMatch:
|
.. _minimumShouldMatch:
|
||||||
|
|
||||||
``minimumShouldMatch``
|
``minimumShouldMatch``
|
||||||
|
@ -329,3 +346,20 @@ Searching
|
||||||
factor = 2
|
factor = 2
|
||||||
missing = 1
|
missing = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.. _mode:
|
||||||
|
|
||||||
|
``mode``
|
||||||
|
""""""""
|
||||||
|
|
||||||
|
Used by: Controller while preparing action.
|
||||||
|
|
||||||
|
Define to switch from search to filter mode.
|
||||||
|
|
||||||
|
Example::
|
||||||
|
|
||||||
|
plugin.tx_searchcore.settings.searching {
|
||||||
|
mode = filter
|
||||||
|
}
|
||||||
|
|
||||||
|
Only ``filter`` is allowed as value. Will submit an empty query to switch to filter mode.
|
||||||
|
|
3
Makefile
3
Makefile
|
@ -1,7 +1,8 @@
|
||||||
mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST)))
|
mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST)))
|
||||||
current_dir := $(dir $(mkfile_path))
|
current_dir := $(dir $(mkfile_path))
|
||||||
|
|
||||||
TYPO3_WEB_DIR := $(current_dir).Build/Web
|
TYPO3_WEB_DIR := $(current_dir).Build/web
|
||||||
|
TYPO3_PATH_ROOT := $(current_dir).Build/web
|
||||||
# Allow different versions on travis
|
# Allow different versions on travis
|
||||||
TYPO3_VERSION ?= ~6.2
|
TYPO3_VERSION ?= ~6.2
|
||||||
typo3DatabaseName ?= "searchcore_test"
|
typo3DatabaseName ?= "searchcore_test"
|
||||||
|
|
|
@ -55,7 +55,7 @@ class FilterTest extends AbstractFunctionalTestCase
|
||||||
|
|
||||||
$searchRequest->setFilter(['CType' => 'HTML']);
|
$searchRequest->setFilter(['CType' => 'HTML']);
|
||||||
$result = $searchService->search($searchRequest);
|
$result = $searchService->search($searchRequest);
|
||||||
$this->assertSame('5', $result->getResults()[0]['uid'], 'Did not get the expected result entry.');
|
$this->assertSame(5, (int) $result->getResults()[0]['uid'], 'Did not get the expected result entry.');
|
||||||
$this->assertSame(1, count($result), 'Did not receive the single filtered element.');
|
$this->assertSame(1, count($result), 'Did not receive the single filtered element.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,29 @@ class IndexTcaTableTest extends AbstractFunctionalTestCase
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
public function indexSingleBasicTtContent()
|
||||||
|
{
|
||||||
|
\TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(ObjectManager::class)
|
||||||
|
->get(IndexerFactory::class)
|
||||||
|
->getIndexer('tt_content')
|
||||||
|
->indexDocument(6)
|
||||||
|
;
|
||||||
|
|
||||||
|
$response = $this->client->request('typo3content/_search?q=*:*');
|
||||||
|
|
||||||
|
$this->assertTrue($response->isOK(), 'Elastica did not answer with ok code.');
|
||||||
|
$this->assertSame($response->getData()['hits']['total'], 1, 'Not exactly 1 document was indexed.');
|
||||||
|
$this->assertArraySubset(
|
||||||
|
['_source' => ['header' => 'indexed content element']],
|
||||||
|
$response->getData()['hits']['hits'][0],
|
||||||
|
false,
|
||||||
|
'Record was not indexed.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @test
|
* @test
|
||||||
* @expectedException \Codappix\SearchCore\Domain\Index\IndexingException
|
* @expectedException \Codappix\SearchCore\Domain\Index\IndexingException
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
<sorting>72</sorting>
|
<sorting>72</sorting>
|
||||||
<CType>header</CType>
|
<CType>header</CType>
|
||||||
<header>endtime hidden record</header>
|
<header>endtime hidden record</header>
|
||||||
<bodytext></bodytext>
|
<bodytext>Some content</bodytext>
|
||||||
<media>0</media>
|
<media>0</media>
|
||||||
<layout>0</layout>
|
<layout>0</layout>
|
||||||
<deleted>0</deleted>
|
<deleted>0</deleted>
|
||||||
|
@ -49,7 +49,7 @@
|
||||||
<sorting>72</sorting>
|
<sorting>72</sorting>
|
||||||
<CType>header</CType>
|
<CType>header</CType>
|
||||||
<header>Hidden record</header>
|
<header>Hidden record</header>
|
||||||
<bodytext></bodytext>
|
<bodytext>Some content</bodytext>
|
||||||
<media>0</media>
|
<media>0</media>
|
||||||
<layout>0</layout>
|
<layout>0</layout>
|
||||||
<deleted>0</deleted>
|
<deleted>0</deleted>
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<dataset>
|
||||||
|
<!-- DISABLED PAGES -->
|
||||||
|
<pages>
|
||||||
|
<uid>3</uid>
|
||||||
|
<pid>2</pid>
|
||||||
|
<title>Some disabled page due broken root line</title>
|
||||||
|
</pages>
|
||||||
|
<pages>
|
||||||
|
<uid>4</uid>
|
||||||
|
<pid>3</pid>
|
||||||
|
<title>Some disabled page due to parent pages root line being broken</title>
|
||||||
|
</pages>
|
||||||
|
<!-- ENABLED PAGES -->
|
||||||
|
<pages>
|
||||||
|
<uid>6</uid>
|
||||||
|
<pid>1</pid>
|
||||||
|
<title>Some enabled page due valid root line</title>
|
||||||
|
</pages>
|
||||||
|
</dataset>
|
|
@ -0,0 +1,34 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<dataset>
|
||||||
|
<!-- DISABLED PAGES -->
|
||||||
|
<pages>
|
||||||
|
<uid>2</uid>
|
||||||
|
<pid>1</pid>
|
||||||
|
<title>Some disabled page due to timing</title>
|
||||||
|
<endtime>1502186635</endtime>
|
||||||
|
<extendToSubpages>1</extendToSubpages>
|
||||||
|
</pages>
|
||||||
|
<pages>
|
||||||
|
<uid>3</uid>
|
||||||
|
<pid>2</pid>
|
||||||
|
<title>Some disabled page due to inherited timing</title>
|
||||||
|
</pages>
|
||||||
|
<pages>
|
||||||
|
<uid>4</uid>
|
||||||
|
<pid>1</pid>
|
||||||
|
<title>Some disabled page due to timing</title>
|
||||||
|
<starttime>2147483647</starttime>
|
||||||
|
<extendToSubpages>1</extendToSubpages>
|
||||||
|
</pages>
|
||||||
|
<pages>
|
||||||
|
<uid>5</uid>
|
||||||
|
<pid>4</pid>
|
||||||
|
<title>Some disabled page due to inherited timing</title>
|
||||||
|
</pages>
|
||||||
|
<!-- ENABLED PAGES -->
|
||||||
|
<pages>
|
||||||
|
<uid>6</uid>
|
||||||
|
<pid>1</pid>
|
||||||
|
<title>Some enabled page due to no be below inherited disabled timing</title>
|
||||||
|
</pages>
|
||||||
|
</dataset>
|
21
Tests/Functional/Fixtures/Indexing/PagesIndexer/Recycler.xml
Normal file
21
Tests/Functional/Fixtures/Indexing/PagesIndexer/Recycler.xml
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<dataset>
|
||||||
|
<!-- DISABLED PAGES -->
|
||||||
|
<pages>
|
||||||
|
<uid>2</uid>
|
||||||
|
<pid>1</pid>
|
||||||
|
<title>Some disabled page due being recycler</title>
|
||||||
|
<doktype>255</doktype>
|
||||||
|
</pages>
|
||||||
|
<pages>
|
||||||
|
<uid>3</uid>
|
||||||
|
<pid>2</pid>
|
||||||
|
<title>Some disabled page due to parent page being recycler</title>
|
||||||
|
</pages>
|
||||||
|
<!-- ENABLED PAGES -->
|
||||||
|
<pages>
|
||||||
|
<uid>6</uid>
|
||||||
|
<pid>1</pid>
|
||||||
|
<title>Some enabled page due to no be below recycler</title>
|
||||||
|
</pages>
|
||||||
|
</dataset>
|
|
@ -9,7 +9,7 @@
|
||||||
<sorting>72</sorting>
|
<sorting>72</sorting>
|
||||||
<CType>header</CType>
|
<CType>header</CType>
|
||||||
<header>Also indexable record</header>
|
<header>Also indexable record</header>
|
||||||
<bodytext></bodytext>
|
<bodytext>Some content</bodytext>
|
||||||
<media>0</media>
|
<media>0</media>
|
||||||
<layout>0</layout>
|
<layout>0</layout>
|
||||||
<deleted>0</deleted>
|
<deleted>0</deleted>
|
||||||
|
@ -29,7 +29,7 @@
|
||||||
<sorting>72</sorting>
|
<sorting>72</sorting>
|
||||||
<CType>div</CType>
|
<CType>div</CType>
|
||||||
<header>Not indexed by user where ctype condition</header>
|
<header>Not indexed by user where ctype condition</header>
|
||||||
<bodytext></bodytext>
|
<bodytext>Some content</bodytext>
|
||||||
<media>0</media>
|
<media>0</media>
|
||||||
<layout>0</layout>
|
<layout>0</layout>
|
||||||
<deleted>0</deleted>
|
<deleted>0</deleted>
|
||||||
|
|
|
@ -50,7 +50,6 @@ abstract class AbstractDataHandlerTest extends AbstractFunctionalTestCase
|
||||||
->setMethods(['add', 'update', 'delete'])
|
->setMethods(['add', 'update', 'delete'])
|
||||||
->getMock();
|
->getMock();
|
||||||
|
|
||||||
// This way TYPO3 will use our mock instead of a new instance.
|
GeneralUtility::setSingletonInstance(DataHandlerHook::class, new DataHandlerHook($this->subject));
|
||||||
$GLOBALS['T3_VAR']['getUserObj']['&' . DataHandlerHook::class] = new DataHandlerHook($this->subject);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,8 @@ class ProcessesAllowedTablesTest extends AbstractDataHandlerTest
|
||||||
*/
|
*/
|
||||||
public function deletionWillBeTriggeredForTtContent()
|
public function deletionWillBeTriggeredForTtContent()
|
||||||
{
|
{
|
||||||
$this->subject->expects($this->exactly(1))->method('delete')
|
$this->subject->expects($this->exactly(1))
|
||||||
|
->method('delete')
|
||||||
->with($this->equalTo('tt_content'), $this->equalTo('1'));
|
->with($this->equalTo('tt_content'), $this->equalTo('1'));
|
||||||
|
|
||||||
$tce = GeneralUtility::makeInstance(Typo3DataHandler::class);
|
$tce = GeneralUtility::makeInstance(Typo3DataHandler::class);
|
||||||
|
@ -71,9 +72,9 @@ class ProcessesAllowedTablesTest extends AbstractDataHandlerTest
|
||||||
->with(
|
->with(
|
||||||
$this->equalTo('tt_content'),
|
$this->equalTo('tt_content'),
|
||||||
$this->callback(function ($record) {
|
$this->callback(function ($record) {
|
||||||
return isset($record['uid']) && $record['uid'] === '1'
|
return isset($record['uid']) && $record['uid'] == 1
|
||||||
&& isset($record['pid']) && $record['pid'] === '1'
|
&& isset($record['pid']) && $record['pid'] == 1
|
||||||
&& isset($record['colPos']) && $record['colPos'] === '1'
|
&& isset($record['colPos']) && $record['colPos'] == 1
|
||||||
;
|
;
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
@ -99,9 +100,9 @@ class ProcessesAllowedTablesTest extends AbstractDataHandlerTest
|
||||||
->with(
|
->with(
|
||||||
$this->equalTo('tt_content'),
|
$this->equalTo('tt_content'),
|
||||||
$this->callback(function ($record) {
|
$this->callback(function ($record) {
|
||||||
return isset($record['uid']) && $record['uid'] === 2
|
return isset($record['uid']) && $record['uid'] == 2
|
||||||
&& isset($record['pid']) && $record['pid'] === 1
|
&& isset($record['pid']) && $record['pid'] == 1
|
||||||
&& isset($record['header']) && $record['header'] === 'a new record'
|
&& isset($record['header']) && $record['header'] == 'a new record'
|
||||||
;
|
;
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
|
@ -61,4 +61,44 @@ class PagesIndexerTest extends AbstractFunctionalTestCase
|
||||||
$this->inject($indexer, 'connection', $connection);
|
$this->inject($indexer, 'connection', $connection);
|
||||||
$indexer->indexAllDocuments();
|
$indexer->indexAllDocuments();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
* @dataProvider rootLineDataSets
|
||||||
|
* @param string $dataSetPath
|
||||||
|
*/
|
||||||
|
public function rootLineIsRespectedDuringIndexing($dataSetPath)
|
||||||
|
{
|
||||||
|
$this->importDataSet($dataSetPath);
|
||||||
|
|
||||||
|
$objectManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(ObjectManager::class);
|
||||||
|
$tableName = 'pages';
|
||||||
|
|
||||||
|
$connection = $this->getMockBuilder(Elasticsearch::class)
|
||||||
|
->setMethods(['addDocuments'])
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock();
|
||||||
|
|
||||||
|
$connection->expects($this->once())
|
||||||
|
->method('addDocuments')
|
||||||
|
->with(
|
||||||
|
$this->stringContains($tableName),
|
||||||
|
$this->callback(function ($documents) {
|
||||||
|
return count($documents) === 2;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
$indexer = $objectManager->get(IndexerFactory::class)->getIndexer($tableName);
|
||||||
|
$this->inject($indexer, 'connection', $connection);
|
||||||
|
$indexer->indexAllDocuments();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rootLineDataSets()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'Broken root line' => ['Tests/Functional/Fixtures/Indexing/PagesIndexer/BrokenRootLine.xml'],
|
||||||
|
'Recycler doktype' => ['Tests/Functional/Fixtures/Indexing/PagesIndexer/Recycler.xml'],
|
||||||
|
'Extended timing to sub pages' => ['Tests/Functional/Fixtures/Indexing/PagesIndexer/InheritedTiming.xml'],
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,10 +37,6 @@ class RelationResolverTest extends AbstractFunctionalTestCase
|
||||||
$objectManager = GeneralUtility::makeInstance(ObjectManager::class);
|
$objectManager = GeneralUtility::makeInstance(ObjectManager::class);
|
||||||
$table = 'sys_file';
|
$table = 'sys_file';
|
||||||
|
|
||||||
// Only by adding the field to showitem, it will be processed by FormEngine.
|
|
||||||
// We use this field to test inline relations, as there is only one alternative.
|
|
||||||
$GLOBALS['TCA']['sys_file']['types'][1]['showitem'] .= ',metadata';
|
|
||||||
|
|
||||||
$subject = $objectManager->get(TcaTableService::class, $table);
|
$subject = $objectManager->get(TcaTableService::class, $table);
|
||||||
$record = BackendUtility::getRecord($table, 1);
|
$record = BackendUtility::getRecord($table, 1);
|
||||||
$subject->prepareRecord($record);
|
$subject->prepareRecord($record);
|
||||||
|
|
128
Tests/Unit/Controller/SearchControllerTest.php
Normal file
128
Tests/Unit/Controller/SearchControllerTest.php
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
<?php
|
||||||
|
namespace Codappix\Tests\Unit\Controller;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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\Controller\SearchController;
|
||||||
|
use Codappix\SearchCore\Domain\Model\SearchRequest;
|
||||||
|
use Codappix\SearchCore\Domain\Search\SearchService;
|
||||||
|
use Codappix\SearchCore\Tests\Unit\AbstractUnitTestCase;
|
||||||
|
use TYPO3\CMS\Extbase\Mvc\Web\Request;
|
||||||
|
use TYPO3\CMS\Extbase\Object\ObjectManager;
|
||||||
|
|
||||||
|
class SearchControllerTest extends AbstractUnitTestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var SearchController
|
||||||
|
*/
|
||||||
|
protected $subject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Request
|
||||||
|
*/
|
||||||
|
protected $request;
|
||||||
|
|
||||||
|
public function setUp()
|
||||||
|
{
|
||||||
|
\TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(
|
||||||
|
\TYPO3\CMS\Core\Cache\CacheManager::class
|
||||||
|
)->setCacheConfigurations([
|
||||||
|
'extbase_object' => [
|
||||||
|
'backend' => \TYPO3\CMS\Core\Cache\Backend\NullBackend::class,
|
||||||
|
],
|
||||||
|
'extbase_datamapfactory_datamap' => [
|
||||||
|
'backend' => \TYPO3\CMS\Core\Cache\Backend\NullBackend::class,
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
$searchService = $this->getMockBuilder(SearchService::class)
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock();
|
||||||
|
$this->request = new Request();
|
||||||
|
|
||||||
|
$this->subject = new SearchController($searchService);
|
||||||
|
$this->inject($this->subject, 'request', $this->request);
|
||||||
|
$this->inject($this->subject, 'objectManager', new ObjectManager());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
public function searchRequestArgumentIsAddedIfModeIsFilterAndArgumentDoesNotExist()
|
||||||
|
{
|
||||||
|
$this->inject($this->subject, 'settings', [
|
||||||
|
'searching' => [
|
||||||
|
'mode' => 'filter',
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->subject->initializeSearchAction();
|
||||||
|
$this->assertInstanceOf(
|
||||||
|
SearchRequest::class,
|
||||||
|
$this->request->getArgument('searchRequest'),
|
||||||
|
'Search request was not created.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
public function searchRequestArgumentIsAddedToExistingArguments()
|
||||||
|
{
|
||||||
|
$this->request->setArguments([
|
||||||
|
'@widget_0' => [
|
||||||
|
'currentPage' => '7',
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
$this->inject($this->subject, 'settings', [
|
||||||
|
'searching' => [
|
||||||
|
'mode' => 'filter',
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->subject->initializeSearchAction();
|
||||||
|
$this->assertInstanceOf(
|
||||||
|
SearchRequest::class,
|
||||||
|
$this->request->getArgument('searchRequest'),
|
||||||
|
'Search request was not created.'
|
||||||
|
);
|
||||||
|
$this->assertSame(
|
||||||
|
['currentPage' => '7'],
|
||||||
|
$this->request->getArgument('@widget_0'),
|
||||||
|
'Existing arguments were not kept.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
public function searchRequestArgumentIsNotAddedIfModeIsNotFilter()
|
||||||
|
{
|
||||||
|
$this->inject($this->subject, 'settings', ['searching' => []]);
|
||||||
|
|
||||||
|
$this->subject->initializeSearchAction();
|
||||||
|
$this->assertFalse(
|
||||||
|
$this->request->hasArgument('searchRequest'),
|
||||||
|
'Search request should not exist.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -60,10 +60,18 @@ class TcaTableServiceTest extends AbstractUnitTestCase
|
||||||
->method('getIfExists')
|
->method('getIfExists')
|
||||||
->withConsecutive(['indexing.table.additionalWhereClause'], ['indexing.table.rootLineBlacklist'])
|
->withConsecutive(['indexing.table.additionalWhereClause'], ['indexing.table.rootLineBlacklist'])
|
||||||
->will($this->onConsecutiveCalls(null, false));
|
->will($this->onConsecutiveCalls(null, false));
|
||||||
|
$this->subject->expects($this->once())
|
||||||
|
->method('getSystemWhereClause')
|
||||||
|
->will($this->returnValue('1=1 AND pages.no_search = 0'));
|
||||||
|
|
||||||
|
$whereClause = $this->subject->getWhereClause();
|
||||||
$this->assertSame(
|
$this->assertSame(
|
||||||
'1=1 AND pages.no_search = 0',
|
'1=1 AND pages.no_search = 0',
|
||||||
$this->subject->getWhereClause()
|
$whereClause->getStatement()
|
||||||
|
);
|
||||||
|
$this->assertSame(
|
||||||
|
[],
|
||||||
|
$whereClause->getParameters()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,10 +84,18 @@ class TcaTableServiceTest extends AbstractUnitTestCase
|
||||||
->method('getIfExists')
|
->method('getIfExists')
|
||||||
->withConsecutive(['indexing.table.additionalWhereClause'], ['indexing.table.rootLineBlacklist'])
|
->withConsecutive(['indexing.table.additionalWhereClause'], ['indexing.table.rootLineBlacklist'])
|
||||||
->will($this->onConsecutiveCalls('table.field = "someValue"', false));
|
->will($this->onConsecutiveCalls('table.field = "someValue"', false));
|
||||||
|
$this->subject->expects($this->once())
|
||||||
|
->method('getSystemWhereClause')
|
||||||
|
->will($this->returnValue('1=1 AND pages.no_search = 0'));
|
||||||
|
|
||||||
|
$whereClause = $this->subject->getWhereClause();
|
||||||
$this->assertSame(
|
$this->assertSame(
|
||||||
'1=1 AND pages.no_search = 0 AND table.field = "someValue"',
|
'1=1 AND pages.no_search = 0 AND table.field = "someValue"',
|
||||||
$this->subject->getWhereClause()
|
$whereClause->getStatement()
|
||||||
|
);
|
||||||
|
$this->assertSame(
|
||||||
|
[],
|
||||||
|
$whereClause->getParameters()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -157,13 +157,19 @@ class QueryFactoryTest extends AbstractUnitTestCase
|
||||||
->method('get')
|
->method('get')
|
||||||
->will($this->throwException(new InvalidArgumentException));
|
->will($this->throwException(new InvalidArgumentException));
|
||||||
$searchRequest = new SearchRequest('SearchWord');
|
$searchRequest = new SearchRequest('SearchWord');
|
||||||
$searchRequest->setSize(45);
|
$searchRequest->setLimit(45);
|
||||||
|
$searchRequest->setOffset(35);
|
||||||
|
|
||||||
$query = $this->subject->create($searchRequest);
|
$query = $this->subject->create($searchRequest);
|
||||||
$this->assertSame(
|
$this->assertSame(
|
||||||
45,
|
45,
|
||||||
$query->toArray()['size'],
|
$query->toArray()['size'],
|
||||||
'Size was not added to query.'
|
'Limit was not added to query.'
|
||||||
|
);
|
||||||
|
$this->assertSame(
|
||||||
|
35,
|
||||||
|
$query->toArray()['from'],
|
||||||
|
'From was not added to query.'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -318,4 +324,23 @@ class QueryFactoryTest extends AbstractUnitTestCase
|
||||||
'Boosts were not added to query.'
|
'Boosts were not added to query.'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
public function emptySearchStringWillNotAddSearchToQuery()
|
||||||
|
{
|
||||||
|
$searchRequest = new SearchRequest();
|
||||||
|
|
||||||
|
$this->configuration->expects($this->any())
|
||||||
|
->method('get')
|
||||||
|
->will($this->throwException(new InvalidArgumentException));
|
||||||
|
|
||||||
|
$query = $this->subject->create($searchRequest);
|
||||||
|
$this->assertInstanceOf(
|
||||||
|
stdClass,
|
||||||
|
$query->toArray()['query']['match_all'],
|
||||||
|
'Empty search request does not create expected query.'
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ namespace Copyright\SearchCore\Tests\Unit\Domain\Search;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use Codappix\SearchCore\Configuration\ConfigurationContainerInterface;
|
use Codappix\SearchCore\Configuration\ConfigurationContainerInterface;
|
||||||
|
use Codappix\SearchCore\Configuration\InvalidArgumentException;
|
||||||
use Codappix\SearchCore\Connection\ConnectionInterface;
|
use Codappix\SearchCore\Connection\ConnectionInterface;
|
||||||
use Codappix\SearchCore\Domain\Model\SearchRequest;
|
use Codappix\SearchCore\Domain\Model\SearchRequest;
|
||||||
use Codappix\SearchCore\Domain\Search\SearchService;
|
use Codappix\SearchCore\Domain\Search\SearchService;
|
||||||
|
@ -64,10 +65,14 @@ class SearchServiceTest extends AbstractUnitTestCase
|
||||||
->method('getIfExists')
|
->method('getIfExists')
|
||||||
->withConsecutive(['searching.size'], ['searching.facets'])
|
->withConsecutive(['searching.size'], ['searching.facets'])
|
||||||
->will($this->onConsecutiveCalls(45, null));
|
->will($this->onConsecutiveCalls(45, null));
|
||||||
|
$this->configuration->expects($this->exactly(1))
|
||||||
|
->method('get')
|
||||||
|
->with('searching.filter')
|
||||||
|
->will($this->throwException(new InvalidArgumentException));
|
||||||
$this->connection->expects($this->once())
|
$this->connection->expects($this->once())
|
||||||
->method('search')
|
->method('search')
|
||||||
->with($this->callback(function ($searchRequest) {
|
->with($this->callback(function ($searchRequest) {
|
||||||
return $searchRequest->getSize() === 45;
|
return $searchRequest->getLimit() === 45;
|
||||||
}));
|
}));
|
||||||
|
|
||||||
$searchRequest = new SearchRequest('SearchWord');
|
$searchRequest = new SearchRequest('SearchWord');
|
||||||
|
@ -83,13 +88,94 @@ class SearchServiceTest extends AbstractUnitTestCase
|
||||||
->method('getIfExists')
|
->method('getIfExists')
|
||||||
->withConsecutive(['searching.size'], ['searching.facets'])
|
->withConsecutive(['searching.size'], ['searching.facets'])
|
||||||
->will($this->onConsecutiveCalls(null, null));
|
->will($this->onConsecutiveCalls(null, null));
|
||||||
|
$this->configuration->expects($this->exactly(1))
|
||||||
|
->method('get')
|
||||||
|
->with('searching.filter')
|
||||||
|
->will($this->throwException(new InvalidArgumentException));
|
||||||
$this->connection->expects($this->once())
|
$this->connection->expects($this->once())
|
||||||
->method('search')
|
->method('search')
|
||||||
->with($this->callback(function ($searchRequest) {
|
->with($this->callback(function ($searchRequest) {
|
||||||
return $searchRequest->getSize() === 10;
|
return $searchRequest->getLimit() === 10;
|
||||||
}));
|
}));
|
||||||
|
|
||||||
$searchRequest = new SearchRequest('SearchWord');
|
$searchRequest = new SearchRequest('SearchWord');
|
||||||
$this->subject->search($searchRequest);
|
$this->subject->search($searchRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
public function configuredFilterAreAddedToRequestWithoutAnyFilter()
|
||||||
|
{
|
||||||
|
$this->configuration->expects($this->exactly(2))
|
||||||
|
->method('getIfExists')
|
||||||
|
->withConsecutive(['searching.size'], ['searching.facets'])
|
||||||
|
->will($this->onConsecutiveCalls(null, null));
|
||||||
|
$this->configuration->expects($this->exactly(1))
|
||||||
|
->method('get')
|
||||||
|
->with('searching.filter')
|
||||||
|
->willReturn(['property' => 'something']);
|
||||||
|
|
||||||
|
$this->connection->expects($this->once())
|
||||||
|
->method('search')
|
||||||
|
->with($this->callback(function ($searchRequest) {
|
||||||
|
return $searchRequest->getFilter() === ['property' => 'something'];
|
||||||
|
}));
|
||||||
|
|
||||||
|
$searchRequest = new SearchRequest('SearchWord');
|
||||||
|
$this->subject->search($searchRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
public function configuredFilterAreAddedToRequestWithExistingFilter()
|
||||||
|
{
|
||||||
|
$this->configuration->expects($this->exactly(2))
|
||||||
|
->method('getIfExists')
|
||||||
|
->withConsecutive(['searching.size'], ['searching.facets'])
|
||||||
|
->will($this->onConsecutiveCalls(null, null));
|
||||||
|
$this->configuration->expects($this->exactly(1))
|
||||||
|
->method('get')
|
||||||
|
->with('searching.filter')
|
||||||
|
->willReturn(['property' => 'something']);
|
||||||
|
|
||||||
|
$this->connection->expects($this->once())
|
||||||
|
->method('search')
|
||||||
|
->with($this->callback(function ($searchRequest) {
|
||||||
|
return $searchRequest->getFilter() === [
|
||||||
|
'anotherProperty' => 'anything',
|
||||||
|
'property' => 'something',
|
||||||
|
];
|
||||||
|
}));
|
||||||
|
|
||||||
|
$searchRequest = new SearchRequest('SearchWord');
|
||||||
|
$searchRequest->setFilter(['anotherProperty' => 'anything']);
|
||||||
|
$this->subject->search($searchRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
public function nonConfiguredFilterIsNotChangingRequestWithExistingFilter()
|
||||||
|
{
|
||||||
|
$this->configuration->expects($this->exactly(2))
|
||||||
|
->method('getIfExists')
|
||||||
|
->withConsecutive(['searching.size'], ['searching.facets'])
|
||||||
|
->will($this->onConsecutiveCalls(null, null));
|
||||||
|
$this->configuration->expects($this->exactly(1))
|
||||||
|
->method('get')
|
||||||
|
->with('searching.filter')
|
||||||
|
->will($this->throwException(new InvalidArgumentException));
|
||||||
|
|
||||||
|
$this->connection->expects($this->once())
|
||||||
|
->method('search')
|
||||||
|
->with($this->callback(function ($searchRequest) {
|
||||||
|
return $searchRequest->getFilter() === ['anotherProperty' => 'anything'];
|
||||||
|
}));
|
||||||
|
|
||||||
|
$searchRequest = new SearchRequest('SearchWord');
|
||||||
|
$searchRequest->setFilter(['anotherProperty' => 'anything']);
|
||||||
|
$this->subject->search($searchRequest);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,14 +30,14 @@
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"post-autoload-dump": [
|
"post-autoload-dump": [
|
||||||
"mkdir -p .Build/Web/typo3conf/ext/",
|
"mkdir -p .Build/web/typo3conf/ext/",
|
||||||
"[ -L .Build/Web/typo3conf/ext/search_core ] || ln -snvf ../../../../. .Build/Web/typo3conf/ext/search_core"
|
"[ -L .Build/web/typo3conf/ext/search_core ] || ln -snvf ../../../../. .Build/web/typo3conf/ext/search_core"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"extra": {
|
"extra": {
|
||||||
"typo3/cms": {
|
"typo3/cms": {
|
||||||
"cms-package-dir": "{$vendor-dir}/typo3/cms",
|
"cms-package-dir": "{$vendor-dir}/typo3/cms",
|
||||||
"web-dir": ".Build/Web"
|
"web-dir": ".Build/web"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"authors": [
|
"authors": [
|
||||||
|
|
|
@ -16,10 +16,10 @@ call_user_func(
|
||||||
],
|
],
|
||||||
't3lib/class.t3lib_tcemain.php' => [
|
't3lib/class.t3lib_tcemain.php' => [
|
||||||
'processCmdmapClass' => [
|
'processCmdmapClass' => [
|
||||||
$extensionKey => '&' . \Codappix\SearchCore\Hook\DataHandler::class,
|
$extensionKey => \Codappix\SearchCore\Hook\DataHandler::class,
|
||||||
],
|
],
|
||||||
'processDatamapClass' => [
|
'processDatamapClass' => [
|
||||||
$extensionKey => '&' . \Codappix\SearchCore\Hook\DataHandler::class,
|
$extensionKey => \Codappix\SearchCore\Hook\DataHandler::class,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
|
Loading…
Reference in a new issue