From 7940da14a7144bd8903ae61ad2a02cbe2439e4ef Mon Sep 17 00:00:00 2001 From: Benjamin Serfhos Date: Tue, 2 Oct 2018 11:57:35 +0200 Subject: [PATCH 01/73] [TASK] Update elastica version pointer --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 83e5f47b..dc13e7f7 100644 --- a/composer.json +++ b/composer.json @@ -18,7 +18,7 @@ "require": { "php": ">=7.0.0", "typo3/cms": ">= 7.6.0 < 9.0.0", - "ruflin/elastica": "~3.2" + "ruflin/elastica": "^6.0.2" }, "require-dev": { "phpunit/phpunit": "~6.4.4", From a93a7af27f15ed99cf6b0adacc6dec0bc919835a Mon Sep 17 00:00:00 2001 From: Benjamin Serfhos Date: Tue, 2 Oct 2018 16:25:05 +0200 Subject: [PATCH 02/73] [TASK] Add docprops to classes + Updated version pointer + Replaces deprecated ArrayUtility for Core utility --- Classes/Command/IndexCommandController.php | 4 + .../Configuration/ConfigurationContainer.php | 23 +- .../ConfigurationContainerInterface.php | 1 + .../Configuration/ConfigurationUtility.php | 17 +- .../InvalidArgumentException.php | 1 + .../NoConfigurationException.php | 1 + Classes/Connection/ConnectionInterface.php | 15 +- Classes/Connection/Elasticsearch.php | 37 +- .../Connection/Elasticsearch/Connection.php | 3 +- .../Elasticsearch/DocumentFactory.php | 16 +- Classes/Connection/Elasticsearch/Facet.php | 36 +- .../Connection/Elasticsearch/FacetOption.php | 10 +- .../Connection/Elasticsearch/IndexFactory.php | 23 +- .../Elasticsearch/MappingFactory.php | 12 +- .../Connection/Elasticsearch/SearchResult.php | 86 +++- .../Connection/Elasticsearch/TypeFactory.php | 6 +- Classes/Connection/FacetInterface.php | 8 +- Classes/Connection/FacetOptionInterface.php | 13 +- Classes/Connection/FacetRequestInterface.php | 9 +- Classes/Connection/ResultItemInterface.php | 9 +- Classes/Connection/SearchRequestInterface.php | 26 +- Classes/Connection/SearchResultInterface.php | 9 +- Classes/Controller/SearchController.php | 18 +- ...entObjectDataProcessorAdapterProcessor.php | 12 +- Classes/DataProcessing/CopyToProcessor.php | 17 +- Classes/DataProcessing/GeoPointProcessor.php | 21 +- Classes/DataProcessing/ProcessorInterface.php | 6 +- Classes/DataProcessing/RemoveProcessor.php | 8 +- Classes/DataProcessing/Service.php | 12 +- .../TcaRelationResolvingProcessor.php | 21 +- Classes/Database/Doctrine/Join.php | 16 +- Classes/Database/Doctrine/Where.php | 16 +- Classes/Domain/Index/AbstractIndexer.php | 56 ++- Classes/Domain/Index/IndexerFactory.php | 15 +- Classes/Domain/Index/IndexerInterface.php | 5 +- Classes/Domain/Index/IndexingException.php | 1 + .../Index/NoMatchingIndexerException.php | 1 + .../Domain/Index/NoRecordFoundException.php | 1 + Classes/Domain/Index/TcaIndexer.php | 12 +- .../TcaIndexer/InvalidArgumentException.php | 1 + .../Domain/Index/TcaIndexer/PagesIndexer.php | 37 +- .../Index/TcaIndexer/RelationResolver.php | 59 ++- .../Index/TcaIndexer/TcaTableService.php | 133 ++++-- .../Index/TcaIndexer/TcaTableService76.php | 378 ------------------ .../TcaIndexer/TcaTableServiceInterface.php | 40 +- Classes/Domain/Model/FacetRequest.php | 13 +- .../Domain/Model/QueryResultInterfaceStub.php | 25 ++ Classes/Domain/Model/ResultItem.php | 37 +- Classes/Domain/Model/SearchRequest.php | 187 ++++++++- Classes/Domain/Model/SearchResult.php | 56 ++- Classes/Domain/Search/QueryFactory.php | 82 +++- Classes/Domain/Search/SearchService.php | 18 +- Classes/Domain/Service/DataHandler.php | 23 +- Classes/Hook/DataHandler.php | 48 ++- .../Form/Finisher/DataHandlerFinisher.php | 10 +- Classes/Utility/FrontendUtility.php | 6 +- Configuration/TCA/Overrides/sys_template.php | 7 + Configuration/TCA/Overrides/tt_content.php | 11 +- Documentation/source/development.rst | 1 + .../source/development/configuration.rst | 47 +++ Resources/Public/Icons/Extension.svg | 10 + Resources/Public/Icons/Module.svg | 10 + Resources/Public/Icons/Plugin.svg | 10 + ...TablesWithMultipleTablesConfiguredTest.php | 2 +- ...TablesWithMultipleTablesConfiguredTest.php | 2 +- .../Functional/Indexing/PagesIndexerTest.php | 2 + .../ConfigurationUtilityTest.php | 5 + .../DataProcessing/CopyToProcessorTest.php | 3 + .../DataProcessing/GeoPointProcessorTest.php | 3 + .../DataProcessing/RemoveProcessorTest.php | 3 + Tests/Unit/Domain/Model/SearchRequestTest.php | 1 + .../Unit/Domain/Search/SearchServiceTest.php | 2 +- Tests/Unit/Hook/DataHandlerTest.php | 2 + .../Form/Finisher/DataHandlerFinisherTest.php | 4 + ext_emconf.php | 2 +- ext_localconf.php | 94 ++--- ext_tables.php | 13 - 77 files changed, 1298 insertions(+), 692 deletions(-) delete mode 100644 Classes/Domain/Index/TcaIndexer/TcaTableService76.php create mode 100644 Configuration/TCA/Overrides/sys_template.php create mode 100644 Documentation/source/development/configuration.rst create mode 100644 Resources/Public/Icons/Extension.svg create mode 100644 Resources/Public/Icons/Module.svg create mode 100644 Resources/Public/Icons/Plugin.svg delete mode 100644 ext_tables.php diff --git a/Classes/Command/IndexCommandController.php b/Classes/Command/IndexCommandController.php index e0bdeb94..de66c111 100644 --- a/Classes/Command/IndexCommandController.php +++ b/Classes/Command/IndexCommandController.php @@ -1,4 +1,5 @@ settings, $path); + $value = $this->getValueByPath($path); if ($value === null) { throw new InvalidArgumentException( @@ -78,6 +79,20 @@ public function get(string $path) */ public function getIfExists(string $path) { - return ArrayUtility::getValueByPath($this->settings, $path); + return $this->getValueByPath($path); + } + + /** + * @param string $path + * @return mixed + */ + protected function getValueByPath(string $path) + { + try { + return ArrayUtility::getValueByPath($this->settings, $path, '.'); + } catch (\Exception $e) { + // Catch all exceptions to safely handle path retrieval + } + return null; } } diff --git a/Classes/Configuration/ConfigurationContainerInterface.php b/Classes/Configuration/ConfigurationContainerInterface.php index a5cb9617..dec7f674 100644 --- a/Classes/Configuration/ConfigurationContainerInterface.php +++ b/Classes/Configuration/ConfigurationContainerInterface.php @@ -1,4 +1,5 @@ $entry) { diff --git a/Classes/Configuration/InvalidArgumentException.php b/Classes/Configuration/InvalidArgumentException.php index 1f5f8f06..449589d3 100644 --- a/Classes/Configuration/InvalidArgumentException.php +++ b/Classes/Configuration/InvalidArgumentException.php @@ -1,4 +1,5 @@ queryFactory = $queryFactory; } + /** + * @param string $documentType + * @param array $document + */ public function addDocument(string $documentType, array $document) { $this->withType( @@ -122,6 +127,10 @@ function ($type) use ($document) { ); } + /** + * @param string $documentType + * @param string $identifier + */ public function deleteDocument(string $documentType, string $identifier) { try { @@ -139,6 +148,10 @@ function ($type) use ($identifier) { } } + /** + * @param string $documentType + * @param array $document + */ public function updateDocument(string $documentType, array $document) { $this->withType( @@ -149,6 +162,10 @@ function ($type) use ($document) { ); } + /** + * @param string $documentType + * @param array $documents + */ public function addDocuments(string $documentType, array $documents) { $this->withType( @@ -159,11 +176,14 @@ function ($type) use ($documents) { ); } + /** + * @param string $documentType + */ public function deleteIndex(string $documentType) { $index = $this->connection->getClient()->getIndex($this->indexFactory->getIndexName()); - if (! $index->exists()) { + if (!$index->exists()) { $this->logger->notice( 'Index did not exist, therefore was not deleted.', [$documentType, $this->indexFactory->getIndexName()] @@ -176,6 +196,9 @@ public function deleteIndex(string $documentType) /** * Execute given callback with Elastica Type based on provided documentType + * + * @param string $documentType + * @param callable $callback */ protected function withType(string $documentType, callable $callback) { @@ -191,7 +214,11 @@ protected function withType(string $documentType, callable $callback) $type->getIndex()->refresh(); } - public function search(SearchRequestInterface $searchRequest) : SearchResultInterface + /** + * @param SearchRequestInterface $searchRequest + * @return SearchResultInterface + */ + public function search(SearchRequestInterface $searchRequest): SearchResultInterface { $this->logger->debug('Search for', [$searchRequest->getSearchTerm()]); @@ -202,7 +229,11 @@ public function search(SearchRequestInterface $searchRequest) : SearchResultInte return $this->objectManager->get(SearchResult::class, $searchRequest, $search->search()); } - protected function getType(string $documentType) : \Elastica\Type + /** + * @param string $documentType + * @return \Elastica\Type + */ + protected function getType(string $documentType): \Elastica\Type { return $this->typeFactory->getType( $this->indexFactory->getIndex( diff --git a/Classes/Connection/Elasticsearch/Connection.php b/Classes/Connection/Elasticsearch/Connection.php index a5e7d0f7..b671f01e 100644 --- a/Classes/Connection/Elasticsearch/Connection.php +++ b/Classes/Connection/Elasticsearch/Connection.php @@ -1,4 +1,5 @@ elasticaClient; } diff --git a/Classes/Connection/Elasticsearch/DocumentFactory.php b/Classes/Connection/Elasticsearch/DocumentFactory.php index beb091a2..797bf0bf 100644 --- a/Classes/Connection/Elasticsearch/DocumentFactory.php +++ b/Classes/Connection/Elasticsearch/DocumentFactory.php @@ -1,4 +1,5 @@ getDocument($documentType, $document); diff --git a/Classes/Connection/Elasticsearch/Facet.php b/Classes/Connection/Elasticsearch/Facet.php index 27de0769..45aa8653 100644 --- a/Classes/Connection/Elasticsearch/Facet.php +++ b/Classes/Connection/Elasticsearch/Facet.php @@ -1,4 +1,5 @@ */ - protected $options = []; + protected $options; + /** + * Facet constructor. + * @param string $name + * @param array $aggregation + * @param ConfigurationContainerInterface $configuration + */ public function __construct(string $name, array $aggregation, ConfigurationContainerInterface $configuration) { $this->name = $name; @@ -60,12 +66,18 @@ public function __construct(string $name, array $aggregation, ConfigurationConta } } - public function getName() : string + /** + * @return string + */ + public function getName(): string { return $this->name; } - public function getField() : string + /** + * @return string + */ + public function getField(): string { return $this->field; } @@ -75,21 +87,23 @@ public function getField() : string * * @return array */ - public function getOptions() : array + public function getOptions(): array { $this->initOptions(); return $this->options; } + /** + * @return void + */ protected function initOptions() { - if ($this->options !== []) { - return; - } - - foreach ($this->buckets as $bucket) { - $this->options[$bucket['key']] = new FacetOption($bucket); + if ($this->options === null) { + $this->options = []; + foreach ($this->buckets as $bucket) { + $this->options[$bucket['key']] = new FacetOption($bucket); + } } } } diff --git a/Classes/Connection/Elasticsearch/FacetOption.php b/Classes/Connection/Elasticsearch/FacetOption.php index 6b544bb9..b2fd1408 100644 --- a/Classes/Connection/Elasticsearch/FacetOption.php +++ b/Classes/Connection/Elasticsearch/FacetOption.php @@ -1,4 +1,5 @@ count = $bucket['doc_count']; } - public function getName() : string + /** + * @return string + */ + public function getName(): string { return $this->name; } - public function getDisplayName() : string + public function getDisplayName(): string { return $this->displayName; } - public function getCount() : int + public function getCount(): int { return $this->count; } diff --git a/Classes/Connection/Elasticsearch/IndexFactory.php b/Classes/Connection/Elasticsearch/IndexFactory.php index d76edc19..685d6ffd 100644 --- a/Classes/Connection/Elasticsearch/IndexFactory.php +++ b/Classes/Connection/Elasticsearch/IndexFactory.php @@ -1,4 +1,5 @@ configuration->get('connections.elasticsearch.index'); + return (string)$this->configuration->get('connections.elasticsearch.index'); } /** * Get an index bases on TYPO3 table name. + * + * @param Connection $connection + * @param string $documentType + * @return \Elastica\Index */ - public function getIndex(Connection $connection, string $documentType) : \Elastica\Index + public function getIndex(Connection $connection, string $documentType): \Elastica\Index { $index = $connection->getClient()->getIndex($this->getIndexName()); @@ -87,7 +92,11 @@ public function getIndex(Connection $connection, string $documentType) : \Elasti return $index; } - protected function getConfigurationFor(string $documentType) : array + /** + * @param string $documentType + * @return array + */ + protected function getConfigurationFor(string $documentType): array { try { $configuration = $this->configuration->get('indexing.' . $documentType . '.index'); @@ -108,7 +117,11 @@ protected function getConfigurationFor(string $documentType) : array } } - protected function prepareAnalyzerConfiguration(array $analyzer) : array + /** + * @param array $analyzer + * @return array + */ + protected function prepareAnalyzerConfiguration(array $analyzer): array { $fieldsToExplode = ['char_filter', 'filter', 'word_list']; diff --git a/Classes/Connection/Elasticsearch/MappingFactory.php b/Classes/Connection/Elasticsearch/MappingFactory.php index 38825566..9f1f262d 100644 --- a/Classes/Connection/Elasticsearch/MappingFactory.php +++ b/Classes/Connection/Elasticsearch/MappingFactory.php @@ -1,4 +1,5 @@ setType($type); @@ -60,7 +64,11 @@ public function getMapping(\Elastica\Type $type) : \Elastica\Type\Mapping return $mapping; } - protected function getConfiguration(string $identifier) : array + /** + * @param string $identifier + * @return array + */ + protected function getConfiguration(string $identifier): array { try { return $this->configuration->get('indexing.' . $identifier . '.mapping'); diff --git a/Classes/Connection/Elasticsearch/SearchResult.php b/Classes/Connection/Elasticsearch/SearchResult.php index 0f814632..a41bded6 100644 --- a/Classes/Connection/Elasticsearch/SearchResult.php +++ b/Classes/Connection/Elasticsearch/SearchResult.php @@ -1,4 +1,5 @@ */ - protected $facets = []; + protected $facets; /** * @var array */ - protected $results = []; + protected $results; /** * For Iterator interface. @@ -64,6 +63,13 @@ class SearchResult implements SearchResultInterface */ protected $objectManager; + /** + * SearchResult constructor. + * + * @param SearchRequestInterface $searchRequest + * @param \Elastica\ResultSet $result + * @param ObjectManagerInterface $objectManager + */ public function __construct( SearchRequestInterface $searchRequest, \Elastica\ResultSet $result, @@ -77,7 +83,7 @@ public function __construct( /** * @return array */ - public function getResults() : array + public function getResults(): array { $this->initResults(); @@ -89,52 +95,74 @@ public function getResults() : array * * @return array */ - public function getFacets() : array + public function getFacets(): array { $this->initFacets(); return $this->facets; } - public function getCurrentCount() : int + /** + * @return integer + */ + public function getCurrentCount(): int { return $this->result->count(); } + /** + * @return void + */ protected function initResults() { - if ($this->results !== []) { - return; - } - - foreach ($this->result->getResults() as $result) { - $this->results[] = new ResultItem($result->getData(), $result->getParam('_type')); + if ($this->results === null) { + $this->results = []; + foreach ($this->result->getResults() as $result) { + $this->results[] = new ResultItem($result->getData(), $result->getParam('_type')); + } } } + /** + * @return void + */ protected function initFacets() { - if ($this->facets !== [] || !$this->result->hasAggregations()) { - return; - } - - foreach ($this->result->getAggregations() as $aggregationName => $aggregation) { - $this->facets[$aggregationName] = $this->objectManager->get(Facet::class, $aggregationName, $aggregation); + if ($this->facets === null) { + $this->facets = []; + if ($this->result->hasAggregations()) { + foreach ($this->result->getAggregations() as $aggregationName => $aggregation) { + $this->facets[$aggregationName] = $this->objectManager->get(Facet::class, $aggregationName, $aggregation); + } + } } } - // Countable - Interface + /** + * Countable - Interface + * + * @return integer + */ public function count() { return $this->result->getTotalHits(); } - // Iterator - Interface + /** + * Iterator - Interface + * + * @return mixed + */ public function current() { return $this->getResults()[$this->position]; } + /** + * Iterator - Interface + * + * @return mixed + */ public function next() { ++$this->position; @@ -142,21 +170,37 @@ public function next() return $this->current(); } + /** + * Iterator - Interface + * + * @return int|mixed + */ public function key() { return $this->position; } + /** + * Iterator - Interface + * + * @return bool + */ public function valid() { return isset($this->getResults()[$this->position]); } + /** + * Iterator - Interface + */ public function rewind() { $this->position = 0; } + /** + * @return SearchRequestInterface|\TYPO3\CMS\Extbase\Persistence\QueryInterface + */ public function getQuery() { return $this->searchRequest; diff --git a/Classes/Connection/Elasticsearch/TypeFactory.php b/Classes/Connection/Elasticsearch/TypeFactory.php index e84cdd07..ccb8cb82 100644 --- a/Classes/Connection/Elasticsearch/TypeFactory.php +++ b/Classes/Connection/Elasticsearch/TypeFactory.php @@ -1,4 +1,5 @@ getType($documentType); } diff --git a/Classes/Connection/FacetInterface.php b/Classes/Connection/FacetInterface.php index 3ec549d5..f95b5e5a 100644 --- a/Classes/Connection/FacetInterface.php +++ b/Classes/Connection/FacetInterface.php @@ -1,4 +1,5 @@ */ - public function getOptions() : array; + public function getOptions(): array; } diff --git a/Classes/Connection/FacetOptionInterface.php b/Classes/Connection/FacetOptionInterface.php index bf998db1..401699a7 100644 --- a/Classes/Connection/FacetOptionInterface.php +++ b/Classes/Connection/FacetOptionInterface.php @@ -1,4 +1,5 @@ data. * * Used e.g. for dataprocessing. + * + * @return array */ - public function getPlainData() : array; + public function getPlainData(): array; /** * Returns the type of the item. * * That should make it easier to differentiate if multiple * types are returned for one query. + * + * @return string */ - public function getType() : string; + public function getType(): string; } diff --git a/Classes/Connection/SearchRequestInterface.php b/Classes/Connection/SearchRequestInterface.php index a4004472..c49adc8a 100644 --- a/Classes/Connection/SearchRequestInterface.php +++ b/Classes/Connection/SearchRequestInterface.php @@ -1,4 +1,5 @@ */ - public function getFacets() : array; + public function getFacets(): array; /** * Workaround for paginate widget support which will * use the request to build another search. * + * @param ConnectionInterface $connection * @return void */ public function setConnection(ConnectionInterface $connection); @@ -60,6 +73,7 @@ public function setConnection(ConnectionInterface $connection); * Workaround for paginate widget support which will * use the request to build another search. * + * @param SearchService $searchService * @return void */ public function setSearchService(SearchService $searchService); diff --git a/Classes/Connection/SearchResultInterface.php b/Classes/Connection/SearchResultInterface.php index be698fae..83af1b35 100644 --- a/Classes/Connection/SearchResultInterface.php +++ b/Classes/Connection/SearchResultInterface.php @@ -1,4 +1,5 @@ */ - public function getResults() : array; + public function getResults(): array; /** * Return all facets, if any. * * @return array */ - public function getFacets() : array; + public function getFacets(): array; /** * Returns the number of results in current result + * + * @return integer */ - public function getCurrentCount() : int; + public function getCurrentCount(): int; } diff --git a/Classes/Controller/SearchController.php b/Classes/Controller/SearchController.php index e484fcda..59e9df55 100644 --- a/Classes/Controller/SearchController.php +++ b/Classes/Controller/SearchController.php @@ -1,4 +1,5 @@ settings['searching']['mode']) && $this->settings['searching']['mode'] === 'filter' + 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), - ] + ['searchRequest' => $this->objectManager->get(SearchRequest::class)] )); } if ($this->arguments->hasArgument('searchRequest')) { $this->arguments->getArgument('searchRequest')->getPropertyMappingConfiguration() - ->allowAllProperties() - ; + ->allowAllProperties(); } } /** * Process a search and deliver original request and result to view. * - * @param null|SearchRequest $searchRequest + * @param SearchRequest $searchRequest + * @return void */ public function searchAction(SearchRequest $searchRequest = null) { diff --git a/Classes/DataProcessing/ContentObjectDataProcessorAdapterProcessor.php b/Classes/DataProcessing/ContentObjectDataProcessorAdapterProcessor.php index 2b7f5539..2538ebfe 100644 --- a/Classes/DataProcessing/ContentObjectDataProcessorAdapterProcessor.php +++ b/Classes/DataProcessing/ContentObjectDataProcessorAdapterProcessor.php @@ -1,4 +1,5 @@ typoScriptService = $typoScriptService; } - public function processData(array $data, array $configuration) : array + /** + * @param array $data + * @param array $configuration + * @return array + */ + public function processData(array $data, array $configuration): array { $dataProcessor = GeneralUtility::makeInstance($configuration['_dataProcessor']); $contentObjectRenderer = GeneralUtility::makeInstance(ContentObjectRenderer::class); diff --git a/Classes/DataProcessing/CopyToProcessor.php b/Classes/DataProcessing/CopyToProcessor.php index 159701fc..cda934cd 100644 --- a/Classes/DataProcessing/CopyToProcessor.php +++ b/Classes/DataProcessing/CopyToProcessor.php @@ -1,4 +1,5 @@ addArray($target, $from); } else { - $target[] = (string) $from; + $target[] = (string)$from; } $target = array_filter($target); @@ -46,6 +52,11 @@ public function processData(array $record, array $configuration) : array return $record; } + /** + * @param array $target + * @param array $from + * @return void + */ protected function addArray(array &$target, array $from) { foreach ($from as $value) { @@ -54,7 +65,7 @@ protected function addArray(array &$target, array $from) continue; } - $target[] = (string) $value; + $target[] = (string)$value; } } } diff --git a/Classes/DataProcessing/GeoPointProcessor.php b/Classes/DataProcessing/GeoPointProcessor.php index 971e2c47..597aacb9 100644 --- a/Classes/DataProcessing/GeoPointProcessor.php +++ b/Classes/DataProcessing/GeoPointProcessor.php @@ -1,4 +1,5 @@ isApplyable($record, $configuration)) { + if (!$this->isApplyable($record, $configuration)) { return $record; } $record[$configuration['to']] = [ - 'lat' => (float) $record[$configuration['lat']], - 'lon' => (float) $record[$configuration['lon']], + 'lat' => (float)$record[$configuration['lat']], + 'lon' => (float)$record[$configuration['lon']], ]; return $record; } - protected function isApplyable(array $record, array $configuration) : bool + /** + * @param array $record + * @param array $configuration + * @return bool + */ + protected function isApplyable(array $record, array $configuration): bool { if (!isset($record[$configuration['lat']]) || !is_numeric($record[$configuration['lat']]) diff --git a/Classes/DataProcessing/ProcessorInterface.php b/Classes/DataProcessing/ProcessorInterface.php index f7513f2b..9bd722bf 100644 --- a/Classes/DataProcessing/ProcessorInterface.php +++ b/Classes/DataProcessing/ProcessorInterface.php @@ -1,4 +1,5 @@ objectManager = $objectManager; @@ -41,8 +46,11 @@ public function __construct(ObjectManagerInterface $objectManager) * Executes the dataprocessor depending on configuration and returns the result. * * @param array|string $configuration Either the full configuration or only the class name. + * @param array $data + * @param string $recordType + * @return array */ - public function executeDataProcessor($configuration, array $data, string $recordType = '') : array + public function executeDataProcessor($configuration, array $data, string $recordType = ''): array { if (is_string($configuration)) { $configuration = [ @@ -50,7 +58,7 @@ public function executeDataProcessor($configuration, array $data, string $record ]; } - if (!isset($configuration['_table']) && $recordType !== '') { + if ($recordType !== '' && !isset($configuration['_table'])) { $configuration['_table'] = $recordType; } diff --git a/Classes/DataProcessing/TcaRelationResolvingProcessor.php b/Classes/DataProcessing/TcaRelationResolvingProcessor.php index e111d7db..b0ffce8a 100644 --- a/Classes/DataProcessing/TcaRelationResolvingProcessor.php +++ b/Classes/DataProcessing/TcaRelationResolvingProcessor.php @@ -1,4 +1,5 @@ initializeConfiguration($configuration); + /** @var TcaTableServiceInterface $tcaTableService */ $tcaTableService = $this->objectManager->get( TcaTableServiceInterface::class, $configuration['_table'] @@ -69,6 +78,7 @@ public function processData(array $record, array $configuration) : array } /** + * @param array $configuration * @throws \InvalidArgumentException If _table is not configured. */ protected function initializeConfiguration(array &$configuration) @@ -84,7 +94,12 @@ protected function initializeConfiguration(array &$configuration) $configuration['excludeFields'] = GeneralUtility::trimExplode(',', $configuration['excludeFields'], true); } - protected function getRecordToProcess(array $record, array $configuration) : array + /** + * @param array $record + * @param array $configuration + * @return array + */ + protected function getRecordToProcess(array $record, array $configuration): array { if ($configuration['excludeFields'] === []) { return $record; diff --git a/Classes/Database/Doctrine/Join.php b/Classes/Database/Doctrine/Join.php index df1a8c64..99bcaca4 100644 --- a/Classes/Database/Doctrine/Join.php +++ b/Classes/Database/Doctrine/Join.php @@ -1,4 +1,5 @@ table = $table; $this->condition = $condition; } - public function getTable() : string + /** + * @return string + */ + public function getTable(): string { return $this->table; } - public function getCondition() : string + /** + * @return string + */ + public function getCondition(): string { return $this->condition; } diff --git a/Classes/Database/Doctrine/Where.php b/Classes/Database/Doctrine/Where.php index 6586b8aa..21ad2dfa 100644 --- a/Classes/Database/Doctrine/Where.php +++ b/Classes/Database/Doctrine/Where.php @@ -1,4 +1,5 @@ statement = $statement; $this->parameters = $parameters; } - public function getStatement() : string + /** + * @return string + */ + public function getStatement(): string { return $this->statement; } - public function getParameters() : array + /** + * @return array + */ + public function getParameters(): array { return $this->parameters; } diff --git a/Classes/Domain/Index/AbstractIndexer.php b/Classes/Domain/Index/AbstractIndexer.php index b22c0110..12c2e5d9 100644 --- a/Classes/Domain/Index/AbstractIndexer.php +++ b/Classes/Domain/Index/AbstractIndexer.php @@ -1,4 +1,5 @@ logger = $logManager->getLogger(__CLASS__); } + /** + * @param string $identifier + * @return void + */ public function setIdentifier(string $identifier) { $this->identifier = $identifier; } + /** + * AbstractIndexer constructor. + * @param ConnectionInterface $connection + * @param ConfigurationContainerInterface $configuration + */ public function __construct(ConnectionInterface $connection, ConfigurationContainerInterface $configuration) { $this->connection = $connection; $this->configuration = $configuration; } + /** + * @return void + */ public function indexAllDocuments() { $this->logger->info('Start indexing'); @@ -92,11 +105,15 @@ public function indexAllDocuments() $this->logger->info('Finish indexing'); } + /** + * @param string $identifier + * @return void + */ public function indexDocument(string $identifier) { $this->logger->info('Start indexing single record.', [$identifier]); try { - $record = $this->getRecord((int) $identifier); + $record = $this->getRecord((int)$identifier); $this->prepareRecord($record); $this->connection->addDocument($this->getDocumentName(), $record); @@ -107,6 +124,9 @@ public function indexDocument(string $identifier) $this->logger->info('Finish indexing'); } + /** + * @return void + */ public function delete() { $this->logger->info('Start deletion of index.'); @@ -114,7 +134,10 @@ public function delete() $this->logger->info('Finish deletion.'); } - protected function getRecordGenerator() : \Generator + /** + * @return \Generator + */ + protected function getRecordGenerator() { $offset = 0; $limit = $this->getLimit(); @@ -125,6 +148,10 @@ protected function getRecordGenerator() : \Generator } } + /** + * @param array $record + * @return void + */ protected function prepareRecord(array &$record) { try { @@ -138,6 +165,10 @@ protected function prepareRecord(array &$record) $this->handleAbstract($record); } + /** + * @param array $record + * @return void + */ protected function handleAbstract(array &$record) { $record['search_abstract'] = ''; @@ -148,8 +179,9 @@ protected function handleAbstract(array &$record) $this->configuration->get('indexing.' . $this->identifier . '.abstractFields') ); if ($fieldsToUse === []) { - return; + throw new InvalidArgumentException('No fields to use', 1538487209251); } + foreach ($fieldsToUse as $fieldToUse) { if (isset($record[$fieldToUse]) && trim($record[$fieldToUse])) { $record['search_abstract'] = trim($record[$fieldToUse]); @@ -157,28 +189,36 @@ protected function handleAbstract(array &$record) } } } catch (InvalidArgumentException $e) { - return; + // Nothing to do. } } /** * Returns the limit to use to fetch records. + * + * @return integer */ - protected function getLimit() : int + protected function getLimit(): int { // TODO: Make configurable. return 50; } /** + * @param integer $offset + * @param integer $limit * @return array|null */ abstract protected function getRecords(int $offset, int $limit); /** - * @throws NoRecordFoundException If record could not be found. + * @param integer $identifier + * @return array */ - abstract protected function getRecord(int $identifier) : array; + abstract protected function getRecord(int $identifier): array; - abstract protected function getDocumentName() : string; + /** + * @return string + */ + abstract protected function getDocumentName(): string; } diff --git a/Classes/Domain/Index/IndexerFactory.php b/Classes/Domain/Index/IndexerFactory.php index 668111d9..68f3771f 100644 --- a/Classes/Domain/Index/IndexerFactory.php +++ b/Classes/Domain/Index/IndexerFactory.php @@ -1,4 +1,5 @@ buildIndexer($this->configuration->get('indexing.' . $identifier . '.indexer'), $identifier); @@ -71,9 +73,12 @@ public function getIndexer(string $identifier) : IndexerInterface } /** - * @throws NoMatchingIndexer + * @param string $indexerClass + * @param string $identifier + * @return \Codappix\SearchCore\Domain\Index\IndexerInterface + * @throws NoMatchingIndexerException */ - protected function buildIndexer(string $indexerClass, string $identifier) : IndexerInterface + protected function buildIndexer(string $indexerClass, string $identifier): IndexerInterface { $indexer = null; if (is_subclass_of($indexerClass, TcaIndexer\PagesIndexer::class) diff --git a/Classes/Domain/Index/IndexerInterface.php b/Classes/Domain/Index/IndexerInterface.php index 4acfb289..cd9ad53c 100644 --- a/Classes/Domain/Index/IndexerInterface.php +++ b/Classes/Domain/Index/IndexerInterface.php @@ -1,4 +1,5 @@ tcaTableService->getRecord($identifier); @@ -84,7 +89,10 @@ protected function getRecord(int $identifier) : array return $record; } - protected function getDocumentName() : string + /** + * @return string + */ + protected function getDocumentName(): string { return $this->tcaTableService->getTableName(); } diff --git a/Classes/Domain/Index/TcaIndexer/InvalidArgumentException.php b/Classes/Domain/Index/TcaIndexer/InvalidArgumentException.php index bc2036fc..dda027a5 100644 --- a/Classes/Domain/Index/TcaIndexer/InvalidArgumentException.php +++ b/Classes/Domain/Index/TcaIndexer/InvalidArgumentException.php @@ -1,4 +1,5 @@ contentTableService = $contentTableService; } + /** + * @param array $record + */ protected function prepareRecord(array &$record) { parent::prepareRecord($record); @@ -78,7 +81,11 @@ protected function prepareRecord(array &$record) } } - protected function fetchContentForPage(int $uid) : array + /** + * @param integer $uid + * @return array + */ + protected function fetchContentForPage(int $uid): array { if ($this->contentTableService instanceof TcaTableService) { $queryBuilder = $this->contentTableService->getQuery(); @@ -123,17 +130,31 @@ protected function fetchContentForPage(int $uid) : array ]; } - protected function getContentElementImages(int $uidOfContentElement) : array + /** + * @param integer $uidOfContentElement + * @return array + */ + protected function getContentElementImages(int $uidOfContentElement): array { return $this->fetchSysFileReferenceUids($uidOfContentElement, 'tt_content', 'image'); } - protected function fetchMediaForPage(int $uid) : array + /** + * @param integer $uid + * @return array + */ + protected function fetchMediaForPage(int $uid): array { return $this->fetchSysFileReferenceUids($uid, 'pages', 'media'); } - protected function fetchSysFileReferenceUids(int $uid, string $tablename, string $fieldname) : array + /** + * @param integer $uid + * @param string $tablename + * @param string $fieldname + * @return array + */ + protected function fetchSysFileReferenceUids(int $uid, string $tablename, string $fieldname): array { $imageRelationUids = []; $imageRelations = $this->fileRepository->findByRelation($tablename, $fieldname, $uid); @@ -145,7 +166,11 @@ protected function fetchSysFileReferenceUids(int $uid, string $tablename, string return $imageRelationUids; } - protected function getContentFromContentElement(array $contentElement) : string + /** + * @param array $contentElement + * @return string + */ + protected function getContentFromContentElement(array $contentElement): string { $content = ''; diff --git a/Classes/Domain/Index/TcaIndexer/RelationResolver.php b/Classes/Domain/Index/TcaIndexer/RelationResolver.php index e992577b..db23b4d6 100644 --- a/Classes/Domain/Index/TcaIndexer/RelationResolver.php +++ b/Classes/Domain/Index/TcaIndexer/RelationResolver.php @@ -1,4 +1,5 @@ getLanguageUidColumn()])) { - $record[$column] = (int) $record[$column]; + $record[$column] = (int)$record[$column]; continue; } @@ -58,6 +64,11 @@ public function resolveRelationsForRecord(TcaTableServiceInterface $service, arr return $record; } + /** + * @param string $value + * @param array $tcaColumn + * @return array + */ protected function resolveValue($value, array $tcaColumn) { if ($value === '' || $value === 'N/A') { @@ -74,25 +85,39 @@ protected function resolveValue($value, array $tcaColumn) return []; } - protected function isRelation(array &$config) : bool + /** + * @param array $config + * @return boolean + */ + protected function isRelation(array &$config): bool { return isset($config['foreign_table']) || (isset($config['renderType']) && !in_array($config['renderType'], ['selectSingle', 'inputDateTime'])) - || (isset($config['internal_type']) && strtolower($config['internal_type']) === 'db') - ; + || (isset($config['internal_type']) && strtolower($config['internal_type']) === 'db'); } - protected function resolveForeignDbValue(string $value) : array + /** + * @param string $value + * @return array + */ + protected function resolveForeignDbValue(string $value): array { return array_map('trim', explode(';', $value)); } - protected function resolveInlineValue(string $value) : array + /** + * @param string $value + * @return array + */ + protected function resolveInlineValue(string $value): array { return array_map('trim', explode(',', $value)); } - protected function getUtilityForMode() : string + /** + * @return string + */ + protected function getUtilityForMode(): string { if (TYPO3_MODE === 'BE') { return BackendUtility::class; @@ -101,15 +126,21 @@ protected function getUtilityForMode() : string return FrontendUtility::class; } + /** + * @param array $record + * @param string $column + * @param TcaTableServiceInterface $service + * @return string + */ protected function getColumnValue(array $record, string $column, TcaTableServiceInterface $service): string { $utility = GeneralUtility::makeInstance($this->getUtilityForMode()); return $utility::getProcessedValueExtra( - $service->getTableName(), - $column, - $record[$column], - 0, - $record['uid'] - ) ?? ''; + $service->getTableName(), + $column, + $record[$column], + 0, + $record['uid'] + ) ?? ''; } } diff --git a/Classes/Domain/Index/TcaIndexer/TcaTableService.php b/Classes/Domain/Index/TcaIndexer/TcaTableService.php index 1330e228..e9a35f64 100644 --- a/Classes/Domain/Index/TcaIndexer/TcaTableService.php +++ b/Classes/Domain/Index/TcaIndexer/TcaTableService.php @@ -1,4 +1,5 @@ configuration = $configuration; } - public function getTableName() : string + /** + * @return string + */ + public function getTableName(): string { return $this->tableName; } - public function getTableClause() : string + /** + * @return string + */ + public function getTableClause(): string { return $this->tableName; } - public function getRecords(int $offset, int $limit) : array + /** + * @param integer $offset + * @param integer $limit + * @return array + */ + public function getRecords(int $offset, int $limit): array { $records = $this->getQuery() ->setFirstResult($offset) @@ -123,7 +135,11 @@ public function getRecords(int $offset, int $limit) : array return $records ?: []; } - public function getRecord(int $identifier) : array + /** + * @param integer $identifier + * @return array + */ + public function getRecord(int $identifier): array { $query = $this->getQuery(); $query = $query->andWhere($this->getTableName() . '.uid = ' . $identifier); @@ -132,16 +148,24 @@ public function getRecord(int $identifier) : array return $record ?: []; } + /** + * @param array $records + * @return void + */ public function filterRecordsByRootLineBlacklist(array &$records) { $records = array_filter( $records, function ($record) { - return ! $this->isRecordBlacklistedByRootline($record); + return !$this->isRecordBlacklistedByRootline($record); } ); } + /** + * @param array $record + * @return void + */ public function prepareRecord(array &$record) { if (isset($record['uid']) && !isset($record['search_identifier'])) { @@ -152,7 +176,10 @@ public function prepareRecord(array &$record) } } - protected function getWhereClause() : Where + /** + * @return Where + */ + protected function getWhereClause(): Where { $parameters = []; $whereClause = $this->getSystemWhereClause(); @@ -174,17 +201,19 @@ protected function getWhereClause() : Where return new Where($whereClause, $parameters); } - protected function getFields() : array + /** + * @return array + */ + protected function getFields(): array { $fields = array_merge( - ['uid','pid'], + ['uid', 'pid'], array_filter( array_keys($this->tca['columns']), function ($columnName) { return !$this->isSystemField($columnName) && !$this->isUserField($columnName) - && !$this->isPassthroughField($columnName) - ; + && !$this->isPassthroughField($columnName); } ) ); @@ -197,7 +226,11 @@ function ($columnName) { return $fields; } - protected function getJoins() : array + + /** + * @return array + */ + protected function getJoins(): array { if ($this->tableName === 'pages') { return []; @@ -212,31 +245,40 @@ protected function getJoins() : array * Generate SQL for TYPO3 as a system, to make sure only available records * are fetched. */ - protected function getSystemWhereClause() : string + protected function getSystemWhereClause(): string { $whereClause = '1=1' . BackendUtility::BEenableFields($this->tableName) . BackendUtility::deleteClause($this->tableName) - . ' AND pages.no_search = 0' - ; + . ' AND pages.no_search = 0'; if ($this->tableName !== 'pages') { $whereClause .= BackendUtility::BEenableFields('pages') - . BackendUtility::deleteClause('pages') - ; + . BackendUtility::deleteClause('pages'); } return $whereClause; } - protected function isSystemField(string $columnName) : bool + /** + * @param string $columnName + * @return bool + */ + protected function isSystemField(string $columnName): bool { $systemFields = [ // Versioning fields, // https://docs.typo3.org/typo3cms/TCAReference/Reference/Ctrl/Index.html#versioningws - 't3ver_oid', 't3ver_id', 't3ver_label', 't3ver_wsid', - 't3ver_state', 't3ver_stage', 't3ver_count', 't3ver_tstamp', - 't3ver_move_id', 't3ver_swapmode', + 't3ver_oid', + 't3ver_id', + 't3ver_label', + 't3ver_wsid', + 't3ver_state', + 't3ver_stage', + 't3ver_count', + 't3ver_tstamp', + 't3ver_move_id', + 't3ver_swapmode', $this->tca['ctrl']['transOrigDiffSourceField'], $this->tca['ctrl']['cruser_id'], $this->tca['ctrl']['fe_cruser_id'], @@ -247,22 +289,31 @@ protected function isSystemField(string $columnName) : bool return in_array($columnName, $systemFields); } - protected function isUserField(string $columnName) : bool + /** + * @param string $columnName + * @return bool + */ + protected function isUserField(string $columnName): bool { $config = $this->getColumnConfig($columnName); return isset($config['type']) && $config['type'] === 'user'; } - protected function isPassthroughField(string $columnName) : bool + /** + * @param string $columnName + * @return bool + */ + protected function isPassthroughField(string $columnName): bool { $config = $this->getColumnConfig($columnName); return isset($config['type']) && $config['type'] === 'passthrough'; } /** - * @throws InvalidArgumentException + * @param string $columnName + * @return array */ - public function getColumnConfig(string $columnName) : array + public function getColumnConfig(string $columnName): array { if (!isset($this->tca['columns'][$columnName])) { throw new InvalidArgumentException( @@ -274,7 +325,10 @@ public function getColumnConfig(string $columnName) : array return $this->tca['columns'][$columnName]['config']; } - public function getLanguageUidColumn() : string + /** + * @return string + */ + public function getLanguageUidColumn(): string { if (!isset($this->tca['ctrl']['languageField'])) { return ''; @@ -290,8 +344,11 @@ public function getLanguageUidColumn() : string * Also further TYPO3 mechanics are taken into account. Does a valid root * line exist, is page inside a recycler, is inherited start- endtime * excluded, etc. + * + * @param array $record + * @return bool */ - protected function isRecordBlacklistedByRootline(array &$record) : bool + protected function isRecordBlacklistedByRootline(array &$record): bool { $pageUid = $record['pid']; if ($this->tableName === 'pages') { @@ -325,9 +382,9 @@ protected function isRecordBlacklistedByRootline(array &$record) : bool } if ($pageInRootLine['extendToSubpages'] && ( - ($pageInRootLine['endtime'] > 0 && $pageInRootLine['endtime'] <= time()) - || ($pageInRootLine['starttime'] > 0 && $pageInRootLine['starttime'] >= time()) - )) { + ($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.', @@ -346,9 +403,9 @@ protected function isRecordBlacklistedByRootline(array &$record) : bool /** * Checks whether any page uids are black listed. */ - protected function isBlackListedRootLineConfigured() : bool + protected function isBlackListedRootLineConfigured(): bool { - return (bool) $this->configuration->getIfExists('indexing.' . $this->getTableName() . '.rootLineBlacklist'); + return (bool)$this->configuration->getIfExists('indexing.' . $this->getTableName() . '.rootLineBlacklist'); } /** @@ -356,7 +413,7 @@ protected function isBlackListedRootLineConfigured() : bool * * @return array */ - protected function getBlackListedRootLine() : array + protected function getBlackListedRootLine(): array { return GeneralUtility::intExplode( ',', @@ -364,7 +421,10 @@ protected function getBlackListedRootLine() : array ); } - public function getQuery() : QueryBuilder + /** + * @return QueryBuilder + */ + public function getQuery(): QueryBuilder { $queryBuilder = $this->getDatabaseConnection()->getQueryBuilderForTable($this->getTableName()); $where = $this->getWhereClause(); @@ -381,7 +441,10 @@ public function getQuery() : QueryBuilder return $query; } - protected function getDatabaseConnection() : ConnectionPool + /** + * @return ConnectionPool + */ + protected function getDatabaseConnection(): ConnectionPool { return GeneralUtility::makeInstance(ConnectionPool::class); } diff --git a/Classes/Domain/Index/TcaIndexer/TcaTableService76.php b/Classes/Domain/Index/TcaIndexer/TcaTableService76.php deleted file mode 100644 index 4445d6d0..00000000 --- a/Classes/Domain/Index/TcaIndexer/TcaTableService76.php +++ /dev/null @@ -1,378 +0,0 @@ - - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -use Codappix\SearchCore\Configuration\ConfigurationContainerInterface; -use Codappix\SearchCore\Domain\Index\IndexingException; -use Codappix\SearchCore\Domain\Index\TcaIndexer\InvalidArgumentException; -use TYPO3\CMS\Backend\Utility\BackendUtility; -use TYPO3\CMS\Core\Utility\GeneralUtility; -use TYPO3\CMS\Core\Utility\RootlineUtility; -use TYPO3\CMS\Extbase\Object\ObjectManagerInterface; - -/** - * Encapsulate logik related to TCA configuration. - */ -class TcaTableService76 implements TcaTableServiceInterface -{ - /** - * TCA for current table. - * !REFERENCE! To save memory. - * @var array - */ - protected $tca; - - /** - * @var string - */ - protected $tableName; - - /** - * @var ConfigurationContainerInterface - */ - protected $configuration; - - /** - * @var \TYPO3\CMS\Core\Log\Logger - */ - protected $logger; - - /** - * @var ObjectManagerInterface - */ - protected $objectManager; - - /** - * 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 ObjectManagerInterface $objectManager - */ - public function injectObjectManager(ObjectManagerInterface $objectManager) - { - $this->objectManager = $objectManager; - } - - /** - * @param string $tableName - * @param ConfigurationContainerInterface $configuration - */ - public function __construct( - $tableName, - ConfigurationContainerInterface $configuration - ) { - if (!isset($GLOBALS['TCA'][$tableName])) { - throw new IndexingException( - 'Table "' . $tableName . '" is not configured in TCA.', - IndexingException::CODE_UNKOWN_TCA_TABLE - ); - } - - $this->tableName = $tableName; - $this->tca = &$GLOBALS['TCA'][$this->tableName]; - $this->configuration = $configuration; - } - - public function getTableName() : string - { - return $this->tableName; - } - - public function getTableClause() : string - { - if ($this->tableName === 'pages') { - return $this->tableName; - } - - return $this->tableName . ' LEFT JOIN pages on ' . $this->tableName . '.pid = pages.uid'; - } - - public function getRecords(int $offset, int $limit) : array - { - $records = $this->getConnection()->exec_SELECTgetRows( - $this->getFields(), - $this->getTableClause(), - $this->getWhereClause(), - '', - '', - (int) $offset . ',' . (int) $limit - ); - - return $records ?: []; - } - - public function getRecord(int $identifier) : array - { - $record = $this->getConnection()->exec_SELECTgetSingleRow( - $this->getFields(), - $this->getTableClause(), - $this->getWhereClause() - . ' AND ' . $this->getTableName() . '.uid = ' . (int) $identifier - ); - - return $record ?: []; - } - - public function filterRecordsByRootLineBlacklist(array &$records) - { - $records = array_filter( - $records, - function ($record) { - return ! $this->isRecordBlacklistedByRootline($record); - } - ); - } - - public function prepareRecord(array &$record) - { - if (isset($record['uid']) && !isset($record['search_identifier'])) { - $record['search_identifier'] = $record['uid']; - } - if (isset($record[$this->tca['ctrl']['label']]) && !isset($record['search_title'])) { - $record['search_title'] = $record[$this->tca['ctrl']['label']]; - } - } - - public function getWhereClause() : string - { - $whereClause = '1=1' - . BackendUtility::BEenableFields($this->tableName) - . BackendUtility::deleteClause($this->tableName) - . ' AND pages.no_search = 0' - ; - - if ($this->tableName !== 'pages') { - $whereClause .= BackendUtility::BEenableFields('pages') - . BackendUtility::deleteClause('pages') - ; - } - - $userDefinedWhere = $this->configuration->getIfExists( - 'indexing.' . $this->getTableName() . '.additionalWhereClause' - ); - if (is_string($userDefinedWhere)) { - $whereClause .= ' AND ' . $userDefinedWhere; - } - if ($this->isBlacklistedRootLineConfigured()) { - $whereClause .= ' AND pages.uid NOT IN (' - . implode(',', $this->getBlacklistedRootLine()) - . ')' - . ' AND pages.pid NOT IN (' - . implode(',', $this->getBlacklistedRootLine()) - . ')'; - } - - $this->logger->debug('Generated where clause.', [$this->tableName, $whereClause]); - return $whereClause; - } - - public function getFields() : string - { - $fields = array_merge( - ['uid','pid'], - array_filter( - array_keys($this->tca['columns']), - function ($columnName) { - return !$this->isSystemField($columnName) - && !$this->isUserField($columnName) - && !$this->isPassthroughField($columnName) - ; - } - ) - ); - - foreach ($fields as $key => $field) { - $fields[$key] = $this->tableName . '.' . $field; - } - - $this->logger->debug('Generated fields.', [$this->tableName, $fields]); - return implode(',', $fields); - } - - - /** - * Generate SQL for TYPO3 as a system, to make sure only available records - * are fetched. - */ - protected function getSystemWhereClause() : string - { - $whereClause = '1=1' - . BackendUtility::BEenableFields($this->tableName) - . BackendUtility::deleteClause($this->tableName) - . ' AND pages.no_search = 0' - ; - - if ($this->tableName !== 'pages') { - $whereClause .= BackendUtility::BEenableFields('pages') - . BackendUtility::deleteClause('pages') - ; - } - - return $whereClause; - } - - protected function isSystemField(string $columnName) : bool - { - $systemFields = [ - // Versioning fields, - // https://docs.typo3.org/typo3cms/TCAReference/Reference/Ctrl/Index.html#versioningws - 't3ver_oid', 't3ver_id', 't3ver_label', 't3ver_wsid', - 't3ver_state', 't3ver_stage', 't3ver_count', 't3ver_tstamp', - 't3ver_move_id', 't3ver_swapmode', - $this->tca['ctrl']['transOrigDiffSourceField'], - $this->tca['ctrl']['cruser_id'], - $this->tca['ctrl']['fe_cruser_id'], - $this->tca['ctrl']['fe_crgroup_id'], - $this->tca['ctrl']['origUid'], - ]; - - return in_array($columnName, $systemFields); - } - - protected function isUserField(string $columnName) : bool - { - $config = $this->getColumnConfig($columnName); - return isset($config['type']) && $config['type'] === 'user'; - } - - protected function isPassthroughField(string $columnName) : bool - { - $config = $this->getColumnConfig($columnName); - return isset($config['type']) && $config['type'] === 'passthrough'; - } - - /** - * @throws InvalidArgumentException - */ - public function getColumnConfig(string $columnName) : array - { - if (!isset($this->tca['columns'][$columnName])) { - throw new InvalidArgumentException( - 'Column does not exist.', - InvalidArgumentException::COLUMN_DOES_NOT_EXIST - ); - } - - return $this->tca['columns'][$columnName]['config']; - } - - public function getLanguageUidColumn() : string - { - if (!isset($this->tca['ctrl']['languageField'])) { - return ''; - } - - return $this->tca['ctrl']['languageField']; - } - - /** - * Checks whether the given record was blacklisted by root line. - * This can be configured by typoscript as whole root lines can be black listed. - * - * Also further TYPO3 mechanics are taken into account. Does a valid root - * line exist, is page inside a recycler, is inherited start- endtime - * excluded, etc. - */ - protected function isRecordBlacklistedByRootline(array &$record) : bool - { - $pageUid = $record['pid']; - if ($this->tableName === 'pages') { - $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; - } - - foreach ($rootline as $pageInRootLine) { - // 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; - } - - 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; - } - } - - return false; - } - - /** - * Checks whether any page uids are black listed. - */ - protected function isBlackListedRootLineConfigured() : bool - { - return (bool) $this->configuration->getIfExists('indexing.' . $this->getTableName() . '.rootLineBlacklist'); - } - - /** - * Get the list of black listed root line page uids. - * - * @return array - */ - protected function getBlackListedRootLine() : array - { - return GeneralUtility::intExplode( - ',', - $this->configuration->getIfExists('indexing.' . $this->getTableName() . '.rootLineBlacklist') - ); - } - - protected function getConnection() : \TYPO3\CMS\Core\Database\DatabaseConnection - { - return $GLOBALS['TYPO3_DB']; - } -} diff --git a/Classes/Domain/Index/TcaIndexer/TcaTableServiceInterface.php b/Classes/Domain/Index/TcaIndexer/TcaTableServiceInterface.php index e4ee7c5e..6025b101 100644 --- a/Classes/Domain/Index/TcaIndexer/TcaTableServiceInterface.php +++ b/Classes/Domain/Index/TcaIndexer/TcaTableServiceInterface.php @@ -1,4 +1,5 @@ config = $config; } - public function getIdentifier() : string + /** + * @return string + */ + public function getIdentifier(): string { return $this->identifier; } - public function getConfig() : array + /** + * @return array + */ + public function getConfig(): array { return $this->config; } diff --git a/Classes/Domain/Model/QueryResultInterfaceStub.php b/Classes/Domain/Model/QueryResultInterfaceStub.php index 960fd40c..980ee894 100644 --- a/Classes/Domain/Model/QueryResultInterfaceStub.php +++ b/Classes/Domain/Model/QueryResultInterfaceStub.php @@ -1,4 +1,5 @@ * @@ -20,8 +23,6 @@ * 02110-1301, USA. */ -use Codappix\SearchCore\Connection\ResultItemInterface; - class ResultItem implements ResultItemInterface { /** @@ -34,37 +35,65 @@ class ResultItem implements ResultItemInterface */ protected $type = ''; + /** + * ResultItem constructor. + * @param array $result + * @param string $type + */ public function __construct(array $result, string $type) { $this->data = $result; $this->type = $type; } - public function getType() : string + /** + * @return string + */ + public function getType(): string { return $this->type; } - public function getPlainData() : array + /** + * @return array + */ + public function getPlainData(): array { return $this->data; } + /** + * @param mixed $offset + * @return bool + */ public function offsetExists($offset) { return isset($this->data[$offset]); } + /** + * @param mixed $offset + * @return mixed + */ public function offsetGet($offset) { return $this->data[$offset]; } + /** + * @param mixed $offset + * @param mixed $value + * @throws \BadMethodCallException + */ public function offsetSet($offset, $value) { throw new \BadMethodCallException('It\'s not possible to change the search result.', 1499179077); } + /** + * @param mixed $offset + * @throws \BadMethodCallException + */ public function offsetUnset($offset) { throw new \BadMethodCallException('It\'s not possible to change the search result.', 1499179077); diff --git a/Classes/Domain/Model/SearchRequest.php b/Classes/Domain/Model/SearchRequest.php index 3c888712..0c66365d 100644 --- a/Classes/Domain/Model/SearchRequest.php +++ b/Classes/Domain/Model/SearchRequest.php @@ -1,4 +1,5 @@ query = $query; } - public function getQuery() : string + /** + * @return string + */ + public function getQuery(): string { return $this->query; } - public function getSearchTerm() : string + /** + * @return string + */ + public function getSearchTerm(): string { return $this->query; } @@ -92,22 +100,30 @@ public function getSearchTerm() : string */ public function setFilter(array $filter) { - $filter = \TYPO3\CMS\Core\Utility\ArrayUtility::removeArrayEntryByValue($filter, ''); - $this->filter = \TYPO3\CMS\Extbase\Utility\ArrayUtility::removeEmptyElementsRecursively($filter); + $filter = ArrayUtility::removeArrayEntryByValue($filter, ''); + $this->filter = ArrayUtility::removeNullValuesRecursive($filter); } - public function hasFilter() : bool + /** + * @return bool + */ + public function hasFilter(): bool { return count($this->filter) > 0; } - public function getFilter() : array + /** + * @return array + */ + public function getFilter(): array { return $this->filter; } /** * Add a facet to gather in this search request. + * + * @param FacetRequestInterface $facet */ public function addFacet(FacetRequestInterface $facet) { @@ -117,7 +133,7 @@ public function addFacet(FacetRequestInterface $facet) /** * Returns all configured facets to fetch in this search request. */ - public function getFacets() : array + public function getFacets(): array { return $this->facets; } @@ -125,28 +141,39 @@ public function getFacets() : array /** * Define connection to use for this request. * Necessary to allow implementation of execute for interface. + * + * @param ConnectionInterface $connection */ public function setConnection(ConnectionInterface $connection) { $this->connection = $connection; } + /** + * @param SearchService $searchService + */ public function setSearchService(SearchService $searchService) { $this->searchService = $searchService; } - // Extbase QueryInterface - // Current implementation covers only paginate widget support. + /** + * Extbase QueryInterface + * Current implementation covers only paginate widget support. + * + * @param bool $returnRawQueryResult + * @return array|\Codappix\SearchCore\Connection\SearchResultInterface|\TYPO3\CMS\Extbase\Persistence\QueryResultInterface + * @throws \InvalidArgumentException + */ public function execute($returnRawQueryResult = false) { - if (! ($this->connection instanceof ConnectionInterface)) { + if (!($this->connection instanceof ConnectionInterface)) { throw new \InvalidArgumentException( 'Connection was not set before, therefore execute can not work. Use `setConnection` before.', 1502197732 ); } - if (! ($this->searchService instanceof SearchService)) { + if (!($this->searchService instanceof SearchService)) { throw new \InvalidArgumentException( 'SearchService was not set before, therefore execute can not work. Use `setSearchService` before.', 1520325175 @@ -156,140 +183,270 @@ public function execute($returnRawQueryResult = false) return $this->searchService->processResult($this->connection->search($this)); } + /** + * @param integer $limit + * @return $this + */ public function setLimit($limit) { - $this->limit = (int) $limit; + $this->limit = (int)$limit; return $this; } + /** + * @param integer $offset + * @return $this + */ public function setOffset($offset) { - $this->offset = (int) $offset; + $this->offset = (int)$offset; return $this; } + /** + * @return integer + */ public function getLimit() { return $this->limit; } + /** + * @return integer + */ public function getOffset() { return $this->offset; } + /** + * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\SourceInterface|void + * @throws \BadMethodCallException + */ public function getSource() { throw new \BadMethodCallException('Method is not implemented yet.', 1502196146); } + /** + * @param array $orderings + * @return \TYPO3\CMS\Extbase\Persistence\QueryInterface|void + * @throws \BadMethodCallException + */ public function setOrderings(array $orderings) { throw new \BadMethodCallException('Method is not implemented yet.', 1502196163); } + /** + * @param \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ConstraintInterface $constraint + * @return \TYPO3\CMS\Extbase\Persistence\QueryInterface|void + * @throws \BadMethodCallException + */ public function matching($constraint) { throw new \BadMethodCallException('Method is not implemented yet.', 1502196197); } + /** + * @param mixed $constraint1 + * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\AndInterface|void + * @throws \BadMethodCallException + */ public function logicalAnd($constraint1) { throw new \BadMethodCallException('Method is not implemented yet.', 1502196166); } + /** + * @param mixed $constraint1 + * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\OrInterface|void + * @throws \BadMethodCallException + */ public function logicalOr($constraint1) { throw new \BadMethodCallException('Method is not implemented yet.', 1502196198); } + /** + * @param \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ConstraintInterface $constraint + * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\NotInterface|void + * @throws \BadMethodCallException + */ public function logicalNot(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\ConstraintInterface $constraint) { throw new \BadMethodCallException('Method is not implemented yet.', 1502196166); } + /** + * @param string $propertyName + * @param mixed $operand + * @param bool $caseSensitive + * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface|void + * @throws \BadMethodCallException + */ public function equals($propertyName, $operand, $caseSensitive = true) { throw new \BadMethodCallException('Method is not implemented yet.', 1502196199); } + /** + * @param string $propertyName + * @param string $operand + * @param bool $caseSensitive + * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface|void + * @throws \BadMethodCallException + */ public function like($propertyName, $operand, $caseSensitive = true) { throw new \BadMethodCallException('Method is not implemented yet.', 1502196167); } + /** + * @param string $propertyName + * @param mixed $operand + * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface|void + * @throws \BadMethodCallException + */ public function contains($propertyName, $operand) { throw new \BadMethodCallException('Method is not implemented yet.', 1502196200); } + /** + * @param string $propertyName + * @param mixed $operand + * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface|void + * @throws \BadMethodCallException + */ public function in($propertyName, $operand) { throw new \BadMethodCallException('Method is not implemented yet.', 1502196167); } + /** + * @param string $propertyName + * @param mixed $operand + * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface|void + * @throws \BadMethodCallException + */ public function lessThan($propertyName, $operand) { throw new \BadMethodCallException('Method is not implemented yet.', 1502196201); } + /** + * @param string $propertyName + * @param mixed $operand + * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface|void + * @throws \BadMethodCallException + */ public function lessThanOrEqual($propertyName, $operand) { throw new \BadMethodCallException('Method is not implemented yet.', 1502196168); } + /** + * @param string $propertyName + * @param mixed $operand + * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface|void + * @throws \BadMethodCallException + */ public function greaterThan($propertyName, $operand) { throw new \BadMethodCallException('Method is not implemented yet.', 1502196202); } + /** + * @param string $propertyName + * @param mixed $operand + * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface|void + * @throws \BadMethodCallException + */ public function greaterThanOrEqual($propertyName, $operand) { throw new \BadMethodCallException('Method is not implemented yet.', 1502196168); } + /** + * @return string|void + * @throws \BadMethodCallException + */ public function getType() { throw new \BadMethodCallException('Method is not implemented yet.', 1502196203); } + /** + * @param \TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface $querySettings + * @throws \BadMethodCallException + */ public function setQuerySettings(\TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface $querySettings) { throw new \BadMethodCallException('Method is not implemented yet.', 1502196168); } + /** + * @return \TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface|void + * @throws \BadMethodCallException + */ public function getQuerySettings() { throw new \BadMethodCallException('Method is not implemented yet.', 1502196205); } + /** + * @return integer|void + * @throws \BadMethodCallException + */ public function count() { throw new \BadMethodCallException('Method is not implemented yet.', 1502196169); } + /** + * @return array|void + * @throws \BadMethodCallException + */ public function getOrderings() { throw new \BadMethodCallException('Method is not implemented yet.', 1502196206); } + /** + * @return null|\TYPO3\CMS\Extbase\Persistence\Generic\Qom\ConstraintInterface|void + * @throws \BadMethodCallException + */ public function getConstraint() { throw new \BadMethodCallException('Method is not implemented yet.', 1502196171); } + /** + * @param string $propertyName + * @return bool|void + * @throws \BadMethodCallException + */ public function isEmpty($propertyName) { throw new \BadMethodCallException('Method is not implemented yet.', 1502196207); } + /** + * @param \TYPO3\CMS\Extbase\Persistence\Generic\Qom\SourceInterface $source + * @throws \BadMethodCallException + */ public function setSource(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\SourceInterface $source) { throw new \BadMethodCallException('Method is not implemented yet.', 1502196172); } + /** + * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\Statement|void + * @throws \BadMethodCallException + */ public function getStatement() { throw new \BadMethodCallException('Method is not implemented yet.', 1502196208); diff --git a/Classes/Domain/Model/SearchResult.php b/Classes/Domain/Model/SearchResult.php index 516c333e..a4f494db 100644 --- a/Classes/Domain/Model/SearchResult.php +++ b/Classes/Domain/Model/SearchResult.php @@ -1,4 +1,5 @@ originalSearchResult = $originalSearchResult; @@ -62,44 +66,60 @@ public function __construct(SearchResultInterface $originalSearchResult, array $ /** * @return array */ - public function getResults() : array + public function getResults(): array { $this->initResults(); return $this->results; } + /** + * @return void + */ protected function initResults() { - if ($this->results !== []) { - return; - } - - foreach ($this->resultItems as $item) { - $this->results[] = new ResultItem($item['data'], $item['type']); + if ($this->results === null) { + foreach ($this->resultItems as $item) { + $this->results[] = new ResultItem($item['data'], $item['type']); + } } } - public function getFacets() : array + /** + * @return array + */ + public function getFacets(): array { return $this->originalSearchResult->getFacets(); } - public function getCurrentCount() : int + /** + * @return integer + */ + public function getCurrentCount(): int { return $this->originalSearchResult->getCurrentCount(); } + /** + * @return integer + */ public function count() { return $this->originalSearchResult->count(); } + /** + * @return mixed + */ public function current() { return $this->getResults()[$this->position]; } + /** + * @return mixed + */ public function next() { ++$this->position; @@ -107,21 +127,33 @@ public function next() return $this->current(); } + /** + * @return integer|mixed + */ public function key() { return $this->position; } + /** + * @return bool + */ public function valid() { return isset($this->getResults()[$this->position]); } + /** + * @return void + */ public function rewind() { $this->position = 0; } + /** + * @return \TYPO3\CMS\Extbase\Persistence\QueryInterface + */ public function getQuery() { return $this->originalSearchResult->getQuery(); diff --git a/Classes/Domain/Search/QueryFactory.php b/Classes/Domain/Search/QueryFactory.php index 98e33247..310d34a6 100644 --- a/Classes/Domain/Search/QueryFactory.php +++ b/Classes/Domain/Search/QueryFactory.php @@ -1,4 +1,5 @@ createElasticaQuery($searchRequest); } - protected function createElasticaQuery(SearchRequestInterface $searchRequest) : \Elastica\Query + /** + * @param SearchRequestInterface $searchRequest + * @return \Elastica\Query + */ + protected function createElasticaQuery(SearchRequestInterface $searchRequest): \Elastica\Query { $query = []; $this->addSize($searchRequest, $query); @@ -83,14 +97,22 @@ protected function createElasticaQuery(SearchRequestInterface $searchRequest) : return new \Elastica\Query($query); } + /** + * @param SearchRequestInterface $searchRequest + * @param array $query + */ protected function addSize(SearchRequestInterface $searchRequest, array &$query) { - $query = ArrayUtility::arrayMergeRecursiveOverrule($query, [ + ArrayUtility::mergeRecursiveWithOverrule($query, [ 'from' => $searchRequest->getOffset(), 'size' => $searchRequest->getLimit(), ]); } + /** + * @param SearchRequestInterface $searchRequest + * @param array $query + */ protected function addSearch(SearchRequestInterface $searchRequest, array &$query) { if (trim($searchRequest->getSearchTerm()) === '') { @@ -108,9 +130,13 @@ protected function addSearch(SearchRequestInterface $searchRequest, array &$quer $matchExpression['minimum_should_match'] = $minimumShouldMatch; } - $query = ArrayUtility::setValueByPath($query, 'query.bool.must.0.multi_match', $matchExpression); + $query = ArrayUtility::setValueByPath($query, 'query.bool.must.0.multi_match', $matchExpression, '.'); } + /** + * @param SearchRequestInterface $searchRequest + * @param array $query + */ protected function addBoosts(SearchRequestInterface $searchRequest, array &$query) { try { @@ -137,7 +163,7 @@ protected function addBoosts(SearchRequestInterface $searchRequest, array &$quer } if (!empty($boostQueryParts)) { - $query = ArrayUtility::arrayMergeRecursiveOverrule($query, [ + ArrayUtility::mergeRecursiveWithOverrule($query, [ 'query' => [ 'bool' => [ 'should' => $boostQueryParts, @@ -147,6 +173,10 @@ protected function addBoosts(SearchRequestInterface $searchRequest, array &$quer } } + /** + * @param array $query + * @return void + */ protected function addFactorBoost(array &$query) { try { @@ -161,10 +191,15 @@ protected function addFactorBoost(array &$query) } } + /** + * @param SearchRequestInterface $searchRequest + * @param array $query + * @return void + */ protected function addFields(SearchRequestInterface $searchRequest, array &$query) { try { - $query = ArrayUtility::arrayMergeRecursiveOverrule($query, [ + ArrayUtility::mergeRecursiveWithOverrule($query, [ 'stored_fields' => GeneralUtility::trimExplode( ',', $this->configuration->get('searching.fields.stored_fields'), @@ -183,26 +218,36 @@ protected function addFields(SearchRequestInterface $searchRequest, array &$quer ); $scriptFields = $this->configurationUtility->filterByCondition($scriptFields); if ($scriptFields !== []) { - $query = ArrayUtility::arrayMergeRecursiveOverrule($query, ['script_fields' => $scriptFields]); + ArrayUtility::mergeRecursiveWithOverrule($query, ['script_fields' => $scriptFields]); } } catch (InvalidArgumentException $e) { // Nothing configured } } + /** + * @param SearchRequestInterface $searchRequest + * @param array $query + * @return void + */ protected function addSort(SearchRequestInterface $searchRequest, array &$query) { $sorting = $this->configuration->getIfExists('searching.sort') ?: []; $sorting = $this->configurationUtility->replaceArrayValuesWithRequestContent($searchRequest, $sorting); $sorting = $this->configurationUtility->filterByCondition($sorting); if ($sorting !== []) { - $query = ArrayUtility::arrayMergeRecursiveOverrule($query, ['sort' => $sorting]); + ArrayUtility::mergeRecursiveWithOverrule($query, ['sort' => $sorting]); } } + /** + * @param SearchRequestInterface $searchRequest + * @param array $query + * @return void + */ protected function addFilter(SearchRequestInterface $searchRequest, array &$query) { - if (! $searchRequest->hasFilter()) { + if (!$searchRequest->hasFilter()) { return; } @@ -215,7 +260,7 @@ protected function addFilter(SearchRequestInterface $searchRequest, array &$quer ); } - $query = ArrayUtility::arrayMergeRecursiveOverrule($query, [ + ArrayUtility::mergeRecursiveWithOverrule($query, [ 'query' => [ 'bool' => [ 'filter' => $filter, @@ -224,7 +269,13 @@ protected function addFilter(SearchRequestInterface $searchRequest, array &$quer ]); } - protected function buildFilter(string $name, $value, array $config) : array + /** + * @param string $name + * @param $value + * @param array $config + * @return array + */ + protected function buildFilter(string $name, $value, array $config): array { if ($config === []) { return [ @@ -257,10 +308,15 @@ protected function buildFilter(string $name, $value, array $config) : array return [$config['field'] => $filter]; } + /** + * @param SearchRequestInterface $searchRequest + * @param array $query + * @return void + */ protected function addFacets(SearchRequestInterface $searchRequest, array &$query) { foreach ($searchRequest->getFacets() as $facet) { - $query = ArrayUtility::arrayMergeRecursiveOverrule($query, [ + ArrayUtility::mergeRecursiveWithOverrule($query, [ 'aggs' => [ $facet->getIdentifier() => $facet->getConfig(), ], diff --git a/Classes/Domain/Search/SearchService.php b/Classes/Domain/Search/SearchService.php index 7c8beeb0..6bb99fb9 100644 --- a/Classes/Domain/Search/SearchService.php +++ b/Classes/Domain/Search/SearchService.php @@ -1,4 +1,5 @@ dataProcessorService = $dataProcessorService; } - public function search(SearchRequestInterface $searchRequest) : SearchResultInterface + /** + * @param SearchRequestInterface $searchRequest + * @return SearchResultInterface + */ + public function search(SearchRequestInterface $searchRequest): SearchResultInterface { $this->addSize($searchRequest); $this->addConfiguredFacets($searchRequest); @@ -89,6 +94,8 @@ public function search(SearchRequestInterface $searchRequest) : SearchResultInte /** * Add configured size of search result items to request. + * + * @param SearchRequestInterface $searchRequest */ protected function addSize(SearchRequestInterface $searchRequest) { @@ -99,6 +106,8 @@ protected function addSize(SearchRequestInterface $searchRequest) /** * Add facets from configuration to request. + * + * @param SearchRequestInterface $searchRequest */ protected function addConfiguredFacets(SearchRequestInterface $searchRequest) { @@ -118,6 +127,8 @@ protected function addConfiguredFacets(SearchRequestInterface $searchRequest) /** * Add filters from configuration, e.g. flexform or TypoScript. + * + * @param SearchRequestInterface $searchRequest */ protected function addConfiguredFilters(SearchRequestInterface $searchRequest) { @@ -137,8 +148,11 @@ protected function addConfiguredFilters(SearchRequestInterface $searchRequest) /** * Processes the result, e.g. applies configured data processing to result. + * + * @param SearchResultInterface $searchResult + * @return SearchResultInterface */ - public function processResult(SearchResultInterface $searchResult) : SearchResultInterface + public function processResult(SearchResultInterface $searchResult): SearchResultInterface { try { $newSearchResultItems = []; diff --git a/Classes/Domain/Service/DataHandler.php b/Classes/Domain/Service/DataHandler.php index de226b90..1e2076f6 100644 --- a/Classes/Domain/Service/DataHandler.php +++ b/Classes/Domain/Service/DataHandler.php @@ -1,4 +1,5 @@ indexerFactory = $indexerFactory; } + /** + * @param string $table + * @param array $record + * @return void + * @throws NoMatchingIndexerException + */ public function update(string $table, array $record) { $this->logger->debug('Record received for update.', [$table, $record]); $this->getIndexer($table)->indexDocument($record['uid']); } + /** + * @param string $table + * @param string $identifier + * @return void + */ public function delete(string $table, string $identifier) { $this->logger->debug('Record received for delete.', [$table, $identifier]); @@ -95,14 +108,20 @@ public function delete(string $table, string $identifier) } /** + * @param string $table + * @return IndexerInterface * @throws NoMatchingIndexerException */ - protected function getIndexer(string $table) : IndexerInterface + protected function getIndexer(string $table): IndexerInterface { return $this->indexerFactory->getIndexer($table); } - public function supportsTable(string $table) : bool + /** + * @param string $table + * @return boolean + */ + public function supportsTable(string $table): bool { try { $this->getIndexer($table); diff --git a/Classes/Hook/DataHandler.php b/Classes/Hook/DataHandler.php index 6c3da5c8..3015cc0f 100644 --- a/Classes/Hook/DataHandler.php +++ b/Classes/Hook/DataHandler.php @@ -1,4 +1,5 @@ shouldProcessHookForTable($table)) { + if (!$this->shouldProcessHookForTable($table)) { $this->logger->debug('Delete not processed.', [$table, $uid]); return false; } - $this->dataHandler->delete($table, (string) $uid); + $this->dataHandler->delete($table, $uid); return true; } + /** + * @param CoreDataHandler $dataHandler + * @return void + * @throws \Codappix\SearchCore\Domain\Index\NoMatchingIndexerException + */ public function processDatamap_afterAllOperations(CoreDataHandler $dataHandler) { foreach ($dataHandler->datamap as $table => $record) { @@ -103,6 +115,12 @@ public function processDatamap_afterAllOperations(CoreDataHandler $dataHandler) } } + /** + * @param array $parameters + * @param CoreDataHandler $dataHandler + * @return void + * @throws \Codappix\SearchCore\Domain\Index\NoMatchingIndexerException + */ public function clearCachePostProc(array $parameters, CoreDataHandler $dataHandler) { $pageUid = 0; @@ -117,13 +135,19 @@ public function clearCachePostProc(array $parameters, CoreDataHandler $dataHandl } if ($pageUid > 0) { - $this->processRecord('pages', (int) $pageUid); + $this->processRecord('pages', (int)$pageUid); } } - protected function processRecord(string $table, int $uid) : bool + /** + * @param string $table + * @param integer $uid + * @return bool + * @throws \Codappix\SearchCore\Domain\Index\NoMatchingIndexerException + */ + protected function processRecord(string $table, int $uid): bool { - if (! $this->shouldProcessHookForTable($table)) { + if (!$this->shouldProcessHookForTable($table)) { $this->logger->debug('Indexing of record not processed.', [$table, $uid]); return false; } @@ -138,13 +162,17 @@ protected function processRecord(string $table, int $uid) : bool return false; } - protected function shouldProcessHookForTable(string $table) : bool + /** + * @param string $table + * @return bool + */ + protected function shouldProcessHookForTable(string $table): bool { if ($this->dataHandler === null) { $this->logger->debug('Datahandler could not be setup.'); return false; } - if (! $this->dataHandler->supportsTable($table)) { + if (!$this->dataHandler->supportsTable($table)) { $this->logger->debug('Table is not allowed.', [$table]); return false; } @@ -155,6 +183,8 @@ protected function shouldProcessHookForTable(string $table) : bool /** * Wrapper to allow unit testing. * + * @param string $table + * @param integer $uid * @return array|null */ protected function getRecord(string $table, int $uid) diff --git a/Classes/Integration/Form/Finisher/DataHandlerFinisher.php b/Classes/Integration/Form/Finisher/DataHandlerFinisher.php index 6a90e015..ee49649f 100644 --- a/Classes/Integration/Form/Finisher/DataHandlerFinisher.php +++ b/Classes/Integration/Form/Finisher/DataHandlerFinisher.php @@ -1,4 +1,5 @@ '', ]; + /** + * @return null|string|void + * @throws FinisherException + * @throws \Codappix\SearchCore\Domain\Index\NoMatchingIndexerException + */ protected function executeInternal() { $action = $this->parseOption('action'); - $record = ['uid' => (int) $this->parseOption('recordUid')]; + $record = ['uid' => (int)$this->parseOption('recordUid')]; $tableName = $this->parseOption('indexIdentifier'); if ($action === '' || $tableName === '' || !is_string($tableName) || $record['uid'] === 0) { @@ -62,7 +68,7 @@ protected function executeInternal() $this->dataHandler->update($tableName, $record); break; case 'delete': - $this->dataHandler->delete($tableName, (string) $record['uid']); + $this->dataHandler->delete($tableName, (string)$record['uid']); break; } } diff --git a/Classes/Utility/FrontendUtility.php b/Classes/Utility/FrontendUtility.php index ffdbb6d4..446bf364 100644 --- a/Classes/Utility/FrontendUtility.php +++ b/Classes/Utility/FrontendUtility.php @@ -1,4 +1,5 @@ registerImplementation( + \Codappix\SearchCore\Configuration\ConfigurationContainerInterface::class, + \YourNamespace\Configuration\SearchCoreConfigurationContainer::class + ); + +SearchCoreConfigurationContainer.php:: + + settings, $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['search_core']); + } + // Or manipulate it your own custom way. + } + } + diff --git a/Resources/Public/Icons/Extension.svg b/Resources/Public/Icons/Extension.svg new file mode 100644 index 00000000..927e60be --- /dev/null +++ b/Resources/Public/Icons/Extension.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/Resources/Public/Icons/Module.svg b/Resources/Public/Icons/Module.svg new file mode 100644 index 00000000..7cc0b632 --- /dev/null +++ b/Resources/Public/Icons/Module.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/Resources/Public/Icons/Plugin.svg b/Resources/Public/Icons/Plugin.svg new file mode 100644 index 00000000..14a0eaed --- /dev/null +++ b/Resources/Public/Icons/Plugin.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/Tests/Functional/Hooks/DataHandler/NonAllowedTablesWithMultipleTablesConfiguredTest.php b/Tests/Functional/Hooks/DataHandler/NonAllowedTablesWithMultipleTablesConfiguredTest.php index ebbee997..d04d416d 100644 --- a/Tests/Functional/Hooks/DataHandler/NonAllowedTablesWithMultipleTablesConfiguredTest.php +++ b/Tests/Functional/Hooks/DataHandler/NonAllowedTablesWithMultipleTablesConfiguredTest.php @@ -26,7 +26,7 @@ protected function getTypoScriptFilesForFrontendRootPage() { return array_merge( parent::getTypoScriptFilesForFrontendRootPage(), - ['EXT:search_core/ Tests/Functional/Fixtures/Hooks/DataHandler/MultipleAllowedTables.ts'] + ['EXT:search_core/Tests/Functional/Fixtures/Hooks/DataHandler/MultipleAllowedTables.ts'] ); } } diff --git a/Tests/Functional/Hooks/DataHandler/ProcessesAllowedTablesWithMultipleTablesConfiguredTest.php b/Tests/Functional/Hooks/DataHandler/ProcessesAllowedTablesWithMultipleTablesConfiguredTest.php index c0b0aa39..a30beb4b 100644 --- a/Tests/Functional/Hooks/DataHandler/ProcessesAllowedTablesWithMultipleTablesConfiguredTest.php +++ b/Tests/Functional/Hooks/DataHandler/ProcessesAllowedTablesWithMultipleTablesConfiguredTest.php @@ -31,7 +31,7 @@ protected function getTypoScriptFilesForFrontendRootPage() { return array_merge( parent::getTypoScriptFilesForFrontendRootPage(), - ['EXT:search_core/ Tests/Functional/Fixtures/Hooks/DataHandler/MultipleAllowedTables.ts'] + ['EXT:search_core/Tests/Functional/Fixtures/Hooks/DataHandler/MultipleAllowedTables.ts'] ); } } diff --git a/Tests/Functional/Indexing/PagesIndexerTest.php b/Tests/Functional/Indexing/PagesIndexerTest.php index acc8b68d..3ac91f44 100644 --- a/Tests/Functional/Indexing/PagesIndexerTest.php +++ b/Tests/Functional/Indexing/PagesIndexerTest.php @@ -68,6 +68,8 @@ public function pagesContainAllAdditionalInformation() * @test * @dataProvider rootLineDataSets * @param string $dataSetPath + * @throws \Codappix\SearchCore\Domain\Index\NoMatchingIndexerException + * @throws \TYPO3\TestingFramework\Core\Exception */ public function rootLineIsRespectedDuringIndexing($dataSetPath) { diff --git a/Tests/Unit/Configuration/ConfigurationUtilityTest.php b/Tests/Unit/Configuration/ConfigurationUtilityTest.php index 4db367c8..23cb8813 100644 --- a/Tests/Unit/Configuration/ConfigurationUtilityTest.php +++ b/Tests/Unit/Configuration/ConfigurationUtilityTest.php @@ -30,6 +30,9 @@ class ConfigurationUtilityTest extends AbstractUnitTestCase /** * @test * @dataProvider possibleRequestAndConfigurationForFluidtemplate + * @param SearchRequestInterface $searchRequest + * @param array $array + * @param array $expected */ public function recursiveEntriesAreProcessedAsFluidtemplate( SearchRequestInterface $searchRequest, @@ -92,6 +95,8 @@ public function possibleRequestAndConfigurationForFluidtemplate() : array /** * @test * @dataProvider possibleConditionEntries + * @param array $entries + * @param array $expected */ public function conditionsAreHandledAsExpected(array $entries, array $expected) { diff --git a/Tests/Unit/DataProcessing/CopyToProcessorTest.php b/Tests/Unit/DataProcessing/CopyToProcessorTest.php index 6968d259..15435a64 100644 --- a/Tests/Unit/DataProcessing/CopyToProcessorTest.php +++ b/Tests/Unit/DataProcessing/CopyToProcessorTest.php @@ -28,6 +28,9 @@ class CopyToProcessorTest extends AbstractUnitTestCase /** * @test * @dataProvider getPossibleDataConfigurationCombinations + * @param array $record + * @param array $configuration + * @param array $expectedData */ public function fieldsAreCopiedAsConfigured(array $record, array $configuration, array $expectedData) { diff --git a/Tests/Unit/DataProcessing/GeoPointProcessorTest.php b/Tests/Unit/DataProcessing/GeoPointProcessorTest.php index 02db659a..8057b422 100644 --- a/Tests/Unit/DataProcessing/GeoPointProcessorTest.php +++ b/Tests/Unit/DataProcessing/GeoPointProcessorTest.php @@ -28,6 +28,9 @@ class GeoPointProcessorTest extends AbstractUnitTestCase /** * @test * @dataProvider getPossibleDataConfigurationCombinations + * @param array $record + * @param array $configuration + * @param array $expectedData */ public function geoPointsAreAddedAsConfigured(array $record, array $configuration, array $expectedData) { diff --git a/Tests/Unit/DataProcessing/RemoveProcessorTest.php b/Tests/Unit/DataProcessing/RemoveProcessorTest.php index cd23d160..c36bc696 100644 --- a/Tests/Unit/DataProcessing/RemoveProcessorTest.php +++ b/Tests/Unit/DataProcessing/RemoveProcessorTest.php @@ -28,6 +28,9 @@ class RemoveProcessorTest extends AbstractUnitTestCase /** * @test * @dataProvider getPossibleDataConfigurationCombinations + * @param array $record + * @param array $configuration + * @param array $expectedData */ public function fieldsAreCopiedAsConfigured(array $record, array $configuration, array $expectedData) { diff --git a/Tests/Unit/Domain/Model/SearchRequestTest.php b/Tests/Unit/Domain/Model/SearchRequestTest.php index 28f90e3c..25ced4e0 100644 --- a/Tests/Unit/Domain/Model/SearchRequestTest.php +++ b/Tests/Unit/Domain/Model/SearchRequestTest.php @@ -31,6 +31,7 @@ class SearchRequestTest extends AbstractUnitTestCase /** * @test * @dataProvider possibleEmptyFilter + * @param array $filter */ public function emptyFilterWillNotBeSet(array $filter) { diff --git a/Tests/Unit/Domain/Search/SearchServiceTest.php b/Tests/Unit/Domain/Search/SearchServiceTest.php index 3b880768..20ff1b4c 100644 --- a/Tests/Unit/Domain/Search/SearchServiceTest.php +++ b/Tests/Unit/Domain/Search/SearchServiceTest.php @@ -100,7 +100,7 @@ public function sizeIsAddedFromConfiguration() ->method('getIfExists') ->withConsecutive(['searching.size'], ['searching.facets']) ->will($this->onConsecutiveCalls(45, null)); - $this->configuration->expects($this->any()) + $this->configuration->expects($this->any()) ->method('get') ->will($this->throwException(new InvalidArgumentException)); $this->connection->expects($this->once()) diff --git a/Tests/Unit/Hook/DataHandlerTest.php b/Tests/Unit/Hook/DataHandlerTest.php index aaf3935c..4cfb8d2b 100644 --- a/Tests/Unit/Hook/DataHandlerTest.php +++ b/Tests/Unit/Hook/DataHandlerTest.php @@ -30,6 +30,8 @@ class DataHandlerToProcessorTest extends AbstractUnitTestCase /** * @test * @dataProvider getPossibleCallCombinations + * @param array $parameters + * @param bool $expectCall */ public function fieldsAreCopiedAsConfigured(array $parameters, bool $expectCall) { diff --git a/Tests/Unit/Integration/Form/Finisher/DataHandlerFinisherTest.php b/Tests/Unit/Integration/Form/Finisher/DataHandlerFinisherTest.php index 30745cd1..a5a7d0e3 100644 --- a/Tests/Unit/Integration/Form/Finisher/DataHandlerFinisherTest.php +++ b/Tests/Unit/Integration/Form/Finisher/DataHandlerFinisherTest.php @@ -63,6 +63,9 @@ public function setUp() * @test * @requires function \TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher::setOptions * @dataProvider possibleFinisherSetup + * @param string $action + * @param array $nonCalledActions + * @param $expectedSecondArgument */ public function validConfiguration(string $action, array $nonCalledActions, $expectedSecondArgument) { @@ -101,6 +104,7 @@ public function possibleFinisherSetup() : array * @test * @requires function \TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher::setOptions * @dataProvider invalidFinisherSetup + * @param array $options */ public function nothingHappensIfUnknownActionIsConfigured(array $options) { diff --git a/ext_emconf.php b/ext_emconf.php index b0bc5ed9..ef4aa923 100644 --- a/ext_emconf.php +++ b/ext_emconf.php @@ -18,7 +18,7 @@ ], ], 'state' => 'beta', - 'version' => '0.0.7', + 'version' => '0.1.0', 'author' => 'Daniel Siepmann', 'author_email' => 'coding@daniel-siepmann.de', ]; diff --git a/ext_localconf.php b/ext_localconf.php index 658d6834..1a1d7c2b 100644 --- a/ext_localconf.php +++ b/ext_localconf.php @@ -1,59 +1,51 @@ to handle records modified through - // Frontend and backend modules not using datahandler - - $GLOBALS['TYPO3_CONF_VARS'] = TYPO3\CMS\Extbase\Utility\ArrayUtility::arrayMergeRecursiveOverrule( - $GLOBALS['TYPO3_CONF_VARS'], - [ - 'SC_OPTIONS' => [ - 'extbase' => [ - 'commandControllers' => [ - Codappix\SearchCore\Command\IndexCommandController::class, - ], +call_user_func(function ($extension) { + // TODO: Add hook for Extbase -> to handle records modified through + // Frontend and backend modules not using datahandler + \TYPO3\CMS\Core\Utility\ArrayUtility::mergeRecursiveWithOverrule( + $GLOBALS['TYPO3_CONF_VARS'], + [ + 'SC_OPTIONS' => [ + 'extbase' => [ + 'commandControllers' => [ + $extension => Codappix\SearchCore\Command\IndexCommandController::class, + ], + ], + 't3lib/class.t3lib_tcemain.php' => [ + 'clearCachePostProc' => [ + $extension => \Codappix\SearchCore\Hook\DataHandler::class . '->clearCachePostProc', ], - 't3lib/class.t3lib_tcemain.php' => [ - 'clearCachePostProc' => [ - $extensionKey => \Codappix\SearchCore\Hook\DataHandler::class . '->clearCachePostProc', - ], - 'processCmdmapClass' => [ - $extensionKey => \Codappix\SearchCore\Hook\DataHandler::class, - ], - 'processDatamapClass' => [ - $extensionKey => \Codappix\SearchCore\Hook\DataHandler::class, - ], + 'processCmdmapClass' => [ + $extension => \Codappix\SearchCore\Hook\DataHandler::class, + ], + 'processDatamapClass' => [ + $extension => \Codappix\SearchCore\Hook\DataHandler::class, ], ], - ] - ); - - TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin( - 'Codappix.' . $extensionKey, - 'search', - [ - 'Search' => 'search' ], - [ - 'Search' => 'search' - ] - ); + ] + ); + + TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin( + 'Codappix.' . $extension, + 'search', + ['Search' => 'search'], + ['Search' => 'search'] + ); - \Codappix\SearchCore\Compatibility\ImplementationRegistrationService::registerImplementations(); + \Codappix\SearchCore\Compatibility\ImplementationRegistrationService::registerImplementations(); - // API does make use of object manager, therefore use GLOBALS - $extensionConfiguration = unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf'][$extensionKey]); - if ($extensionConfiguration === false - || !isset($extensionConfiguration['disable.']['elasticsearch']) - || $extensionConfiguration['disable.']['elasticsearch'] !== '1' - ) { - \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\Object\Container\Container::class) - ->registerImplementation( - \Codappix\SearchCore\Connection\ConnectionInterface::class, - \Codappix\SearchCore\Connection\Elasticsearch::class - ); - } - }, - $_EXTKEY -); + // API does make use of object manager, therefore use GLOBALS + $extensionConfiguration = unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf'][$extension]); + if ($extensionConfiguration === false + || !isset($extensionConfiguration['disable.']['elasticsearch']) + || $extensionConfiguration['disable.']['elasticsearch'] !== '1' + ) { + \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\Object\Container\Container::class) + ->registerImplementation( + \Codappix\SearchCore\Connection\ConnectionInterface::class, + \Codappix\SearchCore\Connection\Elasticsearch::class + ); + } +}, $_EXTKEY); diff --git a/ext_tables.php b/ext_tables.php deleted file mode 100644 index 1a547878..00000000 --- a/ext_tables.php +++ /dev/null @@ -1,13 +0,0 @@ - Date: Wed, 3 Oct 2018 10:59:54 +0200 Subject: [PATCH 03/73] [TASK] Remove deprecated _all field query for Elastic 6.x See: https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-all-field.html --- Classes/Domain/Search/QueryFactory.php | 8 +++-- Configuration/TypoScript/setup.txt | 3 +- .../Private/Templates/Search/Search.html | 29 ++++++++++++------- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/Classes/Domain/Search/QueryFactory.php b/Classes/Domain/Search/QueryFactory.php index 310d34a6..ef859e4f 100644 --- a/Classes/Domain/Search/QueryFactory.php +++ b/Classes/Domain/Search/QueryFactory.php @@ -25,8 +25,8 @@ use Codappix\SearchCore\Configuration\ConfigurationUtility; use Codappix\SearchCore\Configuration\InvalidArgumentException; use Codappix\SearchCore\Connection\SearchRequestInterface; -use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Core\Utility\ArrayUtility; +use TYPO3\CMS\Core\Utility\GeneralUtility; class QueryFactory { @@ -122,9 +122,13 @@ protected function addSearch(SearchRequestInterface $searchRequest, array &$quer $matchExpression = [ 'type' => 'most_fields', 'query' => $searchRequest->getSearchTerm(), - 'fields' => GeneralUtility::trimExplode(',', $this->configuration->get('searching.fields.query')), ]; + $fieldsToQuery = GeneralUtility::trimExplode(',', $this->configuration->getIfExists('searching.fields.query'), true); + if (!empty($fieldsToQuery)) { + $matchExpression['fields'] = $fieldsToQuery; + } + $minimumShouldMatch = $this->configuration->getIfExists('searching.minimumShouldMatch'); if ($minimumShouldMatch) { $matchExpression['minimum_should_match'] = $minimumShouldMatch; diff --git a/Configuration/TypoScript/setup.txt b/Configuration/TypoScript/setup.txt index d3051c17..61441955 100644 --- a/Configuration/TypoScript/setup.txt +++ b/Configuration/TypoScript/setup.txt @@ -26,7 +26,8 @@ plugin { searching { fields { - query = _all + # Default query fields (leave empty for all) + query = } } } diff --git a/Resources/Private/Templates/Search/Search.html b/Resources/Private/Templates/Search/Search.html index dc9e6b26..cfc737e5 100644 --- a/Resources/Private/Templates/Search/Search.html +++ b/Resources/Private/Templates/Search/Search.html @@ -1,13 +1,20 @@ - + + - - - - - {result.id} [{result.type}] - {result.hit._source.search_title} - -
-
+ From d0bbfb8682c500daf268a5b41f6889142fa37bac Mon Sep 17 00:00:00 2001 From: Benjamin Serfhos Date: Wed, 3 Oct 2018 11:49:53 +0200 Subject: [PATCH 04/73] [TASK] Add typolink to index --- Classes/Domain/Index/TcaIndexer/TcaTableService.php | 13 +++++++++++++ Resources/Private/Templates/Search/Search.html | 4 ++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/Classes/Domain/Index/TcaIndexer/TcaTableService.php b/Classes/Domain/Index/TcaIndexer/TcaTableService.php index e9a35f64..74d8538d 100644 --- a/Classes/Domain/Index/TcaIndexer/TcaTableService.php +++ b/Classes/Domain/Index/TcaIndexer/TcaTableService.php @@ -174,6 +174,19 @@ public function prepareRecord(array &$record) if (isset($record[$this->tca['ctrl']['label']]) && !isset($record['search_title'])) { $record['search_title'] = $record[$this->tca['ctrl']['label']]; } + if (!isset($record['search_page_typolink'])) { + switch ($this->tableName) { + case 'pages': + $record['search_page_typolink'] = 't3://page?uid=' . $record['uid']; + break; + case 'sys_file': + $record['search_page_typolink'] = 't3://file?uid=' . $record['uid']; + break; + default: + $record['search_page_typolink'] = 't3://page?uid=' . $record['pid']; + break; + } + } } /** diff --git a/Resources/Private/Templates/Search/Search.html b/Resources/Private/Templates/Search/Search.html index cfc737e5..781b3f0f 100644 --- a/Resources/Private/Templates/Search/Search.html +++ b/Resources/Private/Templates/Search/Search.html @@ -9,9 +9,9 @@
  • - + [{result.type}:{result.plainData.uid}] - {result.plainData.search_title} - +
From de5261f7d49d4511b600d551babf3b1a17251bc9 Mon Sep 17 00:00:00 2001 From: Benjamin Serfhos Date: Thu, 4 Oct 2018 13:01:31 +0200 Subject: [PATCH 05/73] [TASK] Add both form as list plugin seperate --- .../Configuration/ConfigurationContainer.php | 2 +- Classes/Controller/SearchController.php | 23 +++++++++- Configuration/TCA/Overrides/tt_content.php | 23 ++++++++-- .../Mod/Wizards/NewContentElement.tsconfig | 24 ++++++++++ Configuration/TypoScript/constants.txt | 25 ---------- Configuration/TypoScript/constants.typoscript | 30 ++++++++++++ Configuration/TypoScript/setup.txt | 37 --------------- Configuration/TypoScript/setup.typoscript | 46 +++++++++++++++++++ Resources/Private/Language/locallang.xlf | 14 ++++++ Resources/Private/Language/locallang_be.xlf | 20 ++++++++ Resources/Private/Layouts/Default.html | 6 +++ .../Private/Partials/Form/SearchRequest.html | 9 ++++ .../Private/Partials/Results/ListItem.html | 8 ++++ Resources/Private/Templates/Search/Form.html | 11 +++++ .../Private/Templates/Search/Results.html | 25 ++++++++++ .../Private/Templates/Search/Search.html | 20 -------- Resources/Public/Icons/Elastic.svg | 10 ++++ Resources/Public/Icons/Extension.svg | 18 ++++---- Resources/Public/Icons/Module.svg | 10 ---- Resources/Public/Icons/PluginForm.svg | 17 +++++++ .../Icons/{Plugin.svg => PluginResults.svg} | 0 ext_localconf.php | 45 ++++++++++++++---- 22 files changed, 304 insertions(+), 119 deletions(-) create mode 100644 Configuration/TSconfig/Page/Mod/Wizards/NewContentElement.tsconfig delete mode 100644 Configuration/TypoScript/constants.txt create mode 100644 Configuration/TypoScript/constants.typoscript delete mode 100644 Configuration/TypoScript/setup.txt create mode 100644 Configuration/TypoScript/setup.typoscript create mode 100644 Resources/Private/Language/locallang.xlf create mode 100644 Resources/Private/Language/locallang_be.xlf create mode 100644 Resources/Private/Layouts/Default.html create mode 100644 Resources/Private/Partials/Form/SearchRequest.html create mode 100644 Resources/Private/Partials/Results/ListItem.html create mode 100644 Resources/Private/Templates/Search/Form.html create mode 100644 Resources/Private/Templates/Search/Results.html delete mode 100644 Resources/Private/Templates/Search/Search.html create mode 100644 Resources/Public/Icons/Elastic.svg delete mode 100644 Resources/Public/Icons/Module.svg create mode 100644 Resources/Public/Icons/PluginForm.svg rename Resources/Public/Icons/{Plugin.svg => PluginResults.svg} (100%) diff --git a/Classes/Configuration/ConfigurationContainer.php b/Classes/Configuration/ConfigurationContainer.php index 6970f695..1713e717 100644 --- a/Classes/Configuration/ConfigurationContainer.php +++ b/Classes/Configuration/ConfigurationContainer.php @@ -47,7 +47,7 @@ public function injectConfigurationManager(ConfigurationManagerInterface $config $this->settings = $configurationManager->getConfiguration( ConfigurationManagerInterface::CONFIGURATION_TYPE_SETTINGS, 'SearchCore', - 'search' + 'Results' ); if ($this->settings === null) { throw new NoConfigurationException('Could not fetch configuration.', 1484226842); diff --git a/Classes/Controller/SearchController.php b/Classes/Controller/SearchController.php index 59e9df55..51af8a25 100644 --- a/Classes/Controller/SearchController.php +++ b/Classes/Controller/SearchController.php @@ -68,12 +68,31 @@ public function initializeSearchAction() } /** - * Process a search and deliver original request and result to view. + * Action: Search form * * @param SearchRequest $searchRequest * @return void */ - public function searchAction(SearchRequest $searchRequest = null) + public function formAction(SearchRequest $searchRequest = null) + { + $searchResult = null; + if ($searchRequest !== null) { + $searchResult = $this->searchService->search($searchRequest); + } + + $this->view->assignMultiple([ + 'searchRequest' => $searchRequest, + 'searchResult' => $searchResult, + ]); + } + + /** + * Action: Display list results and deliver original request and result to view. + * + * @param SearchRequest $searchRequest + * @return void + */ + public function resultsAction(SearchRequest $searchRequest = null) { $searchResult = null; if ($searchRequest !== null) { diff --git a/Configuration/TCA/Overrides/tt_content.php b/Configuration/TCA/Overrides/tt_content.php index 259150f8..36589eb6 100644 --- a/Configuration/TCA/Overrides/tt_content.php +++ b/Configuration/TCA/Overrides/tt_content.php @@ -1,12 +1,25 @@ + + +
+ + + Please enter your search term in the box above. + + + No results found with given search query (%s). + + + + diff --git a/Resources/Private/Language/locallang_be.xlf b/Resources/Private/Language/locallang_be.xlf new file mode 100644 index 00000000..28a7bb88 --- /dev/null +++ b/Resources/Private/Language/locallang_be.xlf @@ -0,0 +1,20 @@ + + + +
+ + + Search Core: Results + + + List results from search + + + Search Core: Form + + + Just a search form to list page + + + + diff --git a/Resources/Private/Layouts/Default.html b/Resources/Private/Layouts/Default.html new file mode 100644 index 00000000..c12a1372 --- /dev/null +++ b/Resources/Private/Layouts/Default.html @@ -0,0 +1,6 @@ + +
+ +
+ diff --git a/Resources/Private/Partials/Form/SearchRequest.html b/Resources/Private/Partials/Form/SearchRequest.html new file mode 100644 index 00000000..3348de13 --- /dev/null +++ b/Resources/Private/Partials/Form/SearchRequest.html @@ -0,0 +1,9 @@ + + + + + + + + diff --git a/Resources/Private/Partials/Results/ListItem.html b/Resources/Private/Partials/Results/ListItem.html new file mode 100644 index 00000000..7844e324 --- /dev/null +++ b/Resources/Private/Partials/Results/ListItem.html @@ -0,0 +1,8 @@ + + + + [{result.type}:{result.plainData.uid}] - {result.plainData.search_title} + + + diff --git a/Resources/Private/Templates/Search/Form.html b/Resources/Private/Templates/Search/Form.html new file mode 100644 index 00000000..a7002c44 --- /dev/null +++ b/Resources/Private/Templates/Search/Form.html @@ -0,0 +1,11 @@ + + + + +
+ +
+
+ + diff --git a/Resources/Private/Templates/Search/Results.html b/Resources/Private/Templates/Search/Results.html new file mode 100644 index 00000000..f2efc3d6 --- /dev/null +++ b/Resources/Private/Templates/Search/Results.html @@ -0,0 +1,25 @@ + + + + + + +
    + +
  • + +
  • +
    +
+
+ + + {f:translate(key: 'no_results_found_with_search', arguments: '{0: searchRequest.searchTerm}')} + {f:translate(key: 'no_results_found')} + + +
+
+ + diff --git a/Resources/Private/Templates/Search/Search.html b/Resources/Private/Templates/Search/Search.html deleted file mode 100644 index 781b3f0f..00000000 --- a/Resources/Private/Templates/Search/Search.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - diff --git a/Resources/Public/Icons/Elastic.svg b/Resources/Public/Icons/Elastic.svg new file mode 100644 index 00000000..927e60be --- /dev/null +++ b/Resources/Public/Icons/Elastic.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/Resources/Public/Icons/Extension.svg b/Resources/Public/Icons/Extension.svg index 927e60be..7cc0b632 100644 --- a/Resources/Public/Icons/Extension.svg +++ b/Resources/Public/Icons/Extension.svg @@ -1,10 +1,10 @@ - - - - - - - - - + + + + + + + + + diff --git a/Resources/Public/Icons/Module.svg b/Resources/Public/Icons/Module.svg deleted file mode 100644 index 7cc0b632..00000000 --- a/Resources/Public/Icons/Module.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/Resources/Public/Icons/PluginForm.svg b/Resources/Public/Icons/PluginForm.svg new file mode 100644 index 00000000..23adb080 --- /dev/null +++ b/Resources/Public/Icons/PluginForm.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/Resources/Public/Icons/Plugin.svg b/Resources/Public/Icons/PluginResults.svg similarity index 100% rename from Resources/Public/Icons/Plugin.svg rename to Resources/Public/Icons/PluginResults.svg diff --git a/ext_localconf.php b/ext_localconf.php index 1a1d7c2b..2b2e48e2 100644 --- a/ext_localconf.php +++ b/ext_localconf.php @@ -1,6 +1,22 @@ registerIcon( + 'plugin-' . $extension . '-form', + \TYPO3\CMS\Core\Imaging\IconProvider\SvgIconProvider::class, + ['source' => 'EXT:search_core/Resources/Public/Icons/PluginForm.svg'] + ); + $iconRegistry->registerIcon( + 'plugin-' . $extension . '-results', + \TYPO3\CMS\Core\Imaging\IconProvider\SvgIconProvider::class, + ['source' => 'EXT:search_core/Resources/Public/Icons/PluginResults.svg'] + ); + // TODO: Add hook for Extbase -> to handle records modified through // Frontend and backend modules not using datahandler \TYPO3\CMS\Core\Utility\ArrayUtility::mergeRecursiveWithOverrule( @@ -29,18 +45,27 @@ TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin( 'Codappix.' . $extension, - 'search', - ['Search' => 'search'], - ['Search' => 'search'] + 'Results', + ['Search' => 'results'], + ['Search' => 'results'] + ); + + TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin( + 'Codappix.' . $extension, + 'Form', + ['Search' => 'form'], + ['Search' => 'form'] + ); + + \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPageTSConfig( + '' ); \Codappix\SearchCore\Compatibility\ImplementationRegistrationService::registerImplementations(); - // API does make use of object manager, therefore use GLOBALS - $extensionConfiguration = unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf'][$extension]); - if ($extensionConfiguration === false - || !isset($extensionConfiguration['disable.']['elasticsearch']) - || $extensionConfiguration['disable.']['elasticsearch'] !== '1' + if (empty($configuration) || + (isset($configuration['disable.']['elasticsearch']) && + filter_var($configuration['disable.']['elasticsearch'], FILTER_VALIDATE_BOOLEAN) === false) ) { \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\Object\Container\Container::class) ->registerImplementation( @@ -48,4 +73,4 @@ \Codappix\SearchCore\Connection\Elasticsearch::class ); } -}, $_EXTKEY); +}, $_EXTKEY, $_EXTCONF); From 1f0eae88f7e971a75e4b723758710eccb074e36d Mon Sep 17 00:00:00 2001 From: Benjamin Serfhos Date: Mon, 8 Oct 2018 11:57:26 +0200 Subject: [PATCH 06/73] [TASK] Corectly index access group for query content --- Classes/Domain/Index/TcaIndexer/TcaTableService.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Classes/Domain/Index/TcaIndexer/TcaTableService.php b/Classes/Domain/Index/TcaIndexer/TcaTableService.php index 74d8538d..297d0fbc 100644 --- a/Classes/Domain/Index/TcaIndexer/TcaTableService.php +++ b/Classes/Domain/Index/TcaIndexer/TcaTableService.php @@ -174,6 +174,16 @@ public function prepareRecord(array &$record) if (isset($record[$this->tca['ctrl']['label']]) && !isset($record['search_title'])) { $record['search_title'] = $record[$this->tca['ctrl']['label']]; } + if (isset($this->tca['ctrl']['enablecolumns']['fe_group']) && isset($record[$this->tca['ctrl']['enablecolumns']['fe_group']])) { + $groups = GeneralUtility::intExplode( + ',', + $record[$this->tca['ctrl']['enablecolumns']['fe_group']], + true + ); + // Always fallback on public visibility when configured + $record[$this->tca['ctrl']['enablecolumns']['fe_group']] = !empty($groups) ? $groups : [0]; + } + if (!isset($record['search_page_typolink'])) { switch ($this->tableName) { case 'pages': From 397a91e9b0237ced0fe7d9f6f23fc520719ebc24 Mon Sep 17 00:00:00 2001 From: Benjamin Serfhos Date: Wed, 10 Oct 2018 09:52:08 +0200 Subject: [PATCH 07/73] [TASK] Add transparent background color for extension icon --- Resources/Public/Icons/Extension.svg | 1 - 1 file changed, 1 deletion(-) diff --git a/Resources/Public/Icons/Extension.svg b/Resources/Public/Icons/Extension.svg index 7cc0b632..69fa8e87 100644 --- a/Resources/Public/Icons/Extension.svg +++ b/Resources/Public/Icons/Extension.svg @@ -1,5 +1,4 @@ - From e297d556e68ad8abf35524920cf822068b40c1be Mon Sep 17 00:00:00 2001 From: Benjamin Serfhos Date: Thu, 11 Oct 2018 16:50:32 +0200 Subject: [PATCH 08/73] [!!!][FEATURE] Remap specific document type's to ES6 identifiers Multiple types are not allowed any more in ES6. Refactored to use document type and custom identifier to still create different 'types'. See: https://www.elastic.co/guide/en/elasticsearch/reference/6.x/removal-of-types.html --- Classes/Command/IndexCommandController.php | 30 ++++++++---- Classes/Connection/ConnectionInterface.php | 13 ++++- Classes/Connection/Elasticsearch.php | 47 +++++++++++++------ .../Elasticsearch/DocumentFactory.php | 1 - Classes/Domain/Index/AbstractIndexer.php | 22 ++++++++- .../Index/TcaIndexer/TcaTableService.php | 3 -- 6 files changed, 84 insertions(+), 32 deletions(-) diff --git a/Classes/Command/IndexCommandController.php b/Classes/Command/IndexCommandController.php index de66c111..d148deeb 100644 --- a/Classes/Command/IndexCommandController.php +++ b/Classes/Command/IndexCommandController.php @@ -23,6 +23,7 @@ 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; /** @@ -52,12 +53,17 @@ public function injectIndexerFactory(IndexerFactory $factory) */ public function indexCommand(string $identifier) { - try { - $this->indexerFactory->getIndexer($identifier)->indexAllDocuments(); - $this->outputLine($identifier . ' was indexed.'); - } catch (NoMatchingIndexerException $e) { - $this->outputLine('No indexer found for: ' . $identifier); + // Allow multiple identifiers per import task + $identifiers = GeneralUtility::trimExplode(',', $identifier, true); + foreach ($identifiers as $value) { + try { + $this->indexerFactory->getIndexer($value)->indexAllDocuments(); + $this->outputLine($value . ' was indexed.'); + } catch (NoMatchingIndexerException $e) { + $this->outputLine('No indexer found for: ' . $value); + } } + } /** @@ -68,11 +74,15 @@ public function indexCommand(string $identifier) */ public function deleteCommand(string $identifier) { - try { - $this->indexerFactory->getIndexer($identifier)->delete(); - $this->outputLine($identifier . ' was deleted.'); - } catch (NoMatchingIndexerException $e) { - $this->outputLine('No indexer found for: ' . $identifier); + // Allow multiple identifiers per import task + $identifiers = GeneralUtility::trimExplode(',', $identifier, true); + foreach ($identifiers as $value) { + try { + $this->indexerFactory->getIndexer($value)->delete(); + $this->outputLine($value . ' was deleted.'); + } catch (NoMatchingIndexerException $e) { + $this->outputLine('No indexer found for: ' . $value); + } } } } diff --git a/Classes/Connection/ConnectionInterface.php b/Classes/Connection/ConnectionInterface.php index b8af94ae..bad861cb 100644 --- a/Classes/Connection/ConnectionInterface.php +++ b/Classes/Connection/ConnectionInterface.php @@ -21,6 +21,8 @@ * 02110-1301, USA. */ +use Elastica\Query; + /** * Defines interface for connections to storage backend for interacting with documents. */ @@ -77,8 +79,15 @@ public function search(SearchRequestInterface $searchRequest): SearchResultInter /** * Will delete the whole index / db. * - * @param string $documentType * @return void */ - public function deleteIndex(string $documentType); + public function deleteIndex(); + + /** + * Will delete the index / db of defined document type. + * + * @param Query $query + * @return void + */ + public function deleteIndexByQuery(Query $query); } diff --git a/Classes/Connection/Elasticsearch.php b/Classes/Connection/Elasticsearch.php index bf85b5d9..98c12f0a 100644 --- a/Classes/Connection/Elasticsearch.php +++ b/Classes/Connection/Elasticsearch.php @@ -23,8 +23,10 @@ use Codappix\SearchCore\Connection\Elasticsearch\SearchResult; use Codappix\SearchCore\Domain\Search\QueryFactory; +use Elastica\Query; use TYPO3\CMS\Core\SingletonInterface as Singleton; use TYPO3\CMS\Extbase\Object\ObjectManagerInterface; +use TYPO3\CMS\Extbase\Utility\DebuggerUtility; /** * Outer wrapper to elasticsearch. @@ -121,8 +123,8 @@ public function addDocument(string $documentType, array $document) { $this->withType( $documentType, - function ($type) use ($document) { - $type->addDocument($this->documentFactory->getDocument($type->getName(), $document)); + function ($type) use ($documentType, $document) { + $type->addDocument($this->documentFactory->getDocument($documentType, $document)); } ); } @@ -156,8 +158,8 @@ public function updateDocument(string $documentType, array $document) { $this->withType( $documentType, - function ($type) use ($document) { - $type->updateDocument($this->documentFactory->getDocument($type->getName(), $document)); + function ($type) use ($documentType, $document) { + $type->updateDocument($this->documentFactory->getDocument($documentType, $document)); } ); } @@ -170,23 +172,23 @@ public function addDocuments(string $documentType, array $documents) { $this->withType( $documentType, - function ($type) use ($documents) { - $type->addDocuments($this->documentFactory->getDocuments($type->getName(), $documents)); + function ($type) use ($documentType, $documents) { + $type->addDocuments($this->documentFactory->getDocuments($documentType, $documents)); } ); } /** - * @param string $documentType + * @return void */ - public function deleteIndex(string $documentType) + public function deleteIndex() { $index = $this->connection->getClient()->getIndex($this->indexFactory->getIndexName()); if (!$index->exists()) { $this->logger->notice( 'Index did not exist, therefore was not deleted.', - [$documentType, $this->indexFactory->getIndexName()] + [$this->indexFactory->getIndexName()] ); return; } @@ -194,6 +196,24 @@ public function deleteIndex(string $documentType) $index->delete(); } + /** + * @param Query $query + * @return void + */ + public function deleteIndexByQuery(Query $query) + { + $index = $this->connection->getClient()->getIndex($this->indexFactory->getIndexName()); + if (!$index->exists()) { + $this->logger->notice( + 'Index did not exist, therefore items can not be deleted by query.', + [$this->indexFactory->getIndexName(), $query->getQuery()] + ); + return; + } + + $index->deleteByQuery($query); + } + /** * Execute given callback with Elastica Type based on provided documentType * @@ -202,7 +222,7 @@ public function deleteIndex(string $documentType) */ protected function withType(string $documentType, callable $callback) { - $type = $this->getType($documentType); + $type = $this->getType(); // 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. @@ -230,17 +250,16 @@ public function search(SearchRequestInterface $searchRequest): SearchResultInter } /** - * @param string $documentType * @return \Elastica\Type */ - protected function getType(string $documentType): \Elastica\Type + protected function getType(): \Elastica\Type { return $this->typeFactory->getType( $this->indexFactory->getIndex( $this->connection, - $documentType + 'document' ), - $documentType + 'document' ); } } diff --git a/Classes/Connection/Elasticsearch/DocumentFactory.php b/Classes/Connection/Elasticsearch/DocumentFactory.php index 797bf0bf..086fff3b 100644 --- a/Classes/Connection/Elasticsearch/DocumentFactory.php +++ b/Classes/Connection/Elasticsearch/DocumentFactory.php @@ -60,7 +60,6 @@ public function getDocument(string $documentType, array $document): \Elastica\Do } $identifier = $document['search_identifier']; - unset($document['search_identifier']); $this->logger->debug( sprintf('Convert %s %u to document.', $documentType, $identifier), diff --git a/Classes/Domain/Index/AbstractIndexer.php b/Classes/Domain/Index/AbstractIndexer.php index 12c2e5d9..37e2f29c 100644 --- a/Classes/Domain/Index/AbstractIndexer.php +++ b/Classes/Domain/Index/AbstractIndexer.php @@ -24,6 +24,7 @@ use Codappix\SearchCore\Configuration\ConfigurationContainerInterface; use Codappix\SearchCore\Configuration\InvalidArgumentException; use Codappix\SearchCore\Connection\ConnectionInterface; +use Elastica\Query; use TYPO3\CMS\Core\Utility\GeneralUtility; abstract class AbstractIndexer implements IndexerInterface @@ -130,7 +131,13 @@ public function indexDocument(string $identifier) public function delete() { $this->logger->info('Start deletion of index.'); - $this->connection->deleteIndex($this->getDocumentName()); + $this->connection->deleteIndexByQuery(Query::create([ + 'query' => [ + 'regexp' => [ + 'search_identifier' => $this->getDocumentName() . '-*' + ] + ] + ])); $this->logger->info('Finish deletion.'); } @@ -161,10 +168,21 @@ protected function prepareRecord(array &$record) } catch (InvalidArgumentException $e) { // Nothing to do. } - + $this->generateSearchIdentifier($record); $this->handleAbstract($record); } + /** + * @param array $record + * @return void + */ + protected function generateSearchIdentifier(array &$record) + { + if (!isset($record['search_identifier']) && isset($record['uid'])) { + $record['search_identifier'] = $this->getDocumentName() . '-' . $record['uid']; + } + } + /** * @param array $record * @return void diff --git a/Classes/Domain/Index/TcaIndexer/TcaTableService.php b/Classes/Domain/Index/TcaIndexer/TcaTableService.php index 297d0fbc..1d6ea901 100644 --- a/Classes/Domain/Index/TcaIndexer/TcaTableService.php +++ b/Classes/Domain/Index/TcaIndexer/TcaTableService.php @@ -168,9 +168,6 @@ function ($record) { */ public function prepareRecord(array &$record) { - if (isset($record['uid']) && !isset($record['search_identifier'])) { - $record['search_identifier'] = $record['uid']; - } if (isset($record[$this->tca['ctrl']['label']]) && !isset($record['search_title'])) { $record['search_title'] = $record[$this->tca['ctrl']['label']]; } From 404f49aad29e8e94318e2aee39a5b2e50611b1c1 Mon Sep 17 00:00:00 2001 From: Benjamin Serfhos Date: Fri, 12 Oct 2018 18:43:28 +0200 Subject: [PATCH 09/73] [TASK] Add opening for possible user access lookup --- Classes/Controller/SearchController.php | 8 +-- Classes/Domain/Index/AbstractIndexer.php | 7 ++- Classes/Domain/Search/CachedSearchService.php | 55 +++++++++++++++++++ .../Private/Partials/Results/ListItem.html | 4 +- 4 files changed, 66 insertions(+), 8 deletions(-) create mode 100644 Classes/Domain/Search/CachedSearchService.php diff --git a/Classes/Controller/SearchController.php b/Classes/Controller/SearchController.php index 51af8a25..f4f9299d 100644 --- a/Classes/Controller/SearchController.php +++ b/Classes/Controller/SearchController.php @@ -22,7 +22,7 @@ */ use Codappix\SearchCore\Domain\Model\SearchRequest; -use Codappix\SearchCore\Domain\Search\SearchService; +use Codappix\SearchCore\Domain\Search\CachedSearchService; use TYPO3\CMS\Extbase\Mvc\Controller\ActionController; /** @@ -31,14 +31,14 @@ class SearchController extends ActionController { /** - * @var SearchService + * @var CachedSearchService */ protected $searchService; /** - * @param SearchService $searchService + * @param CachedSearchService $searchService */ - public function __construct(SearchService $searchService) + public function __construct(CachedSearchService $searchService) { $this->searchService = $searchService; diff --git a/Classes/Domain/Index/AbstractIndexer.php b/Classes/Domain/Index/AbstractIndexer.php index 37e2f29c..3e3bc55c 100644 --- a/Classes/Domain/Index/AbstractIndexer.php +++ b/Classes/Domain/Index/AbstractIndexer.php @@ -168,7 +168,7 @@ protected function prepareRecord(array &$record) } catch (InvalidArgumentException $e) { // Nothing to do. } - $this->generateSearchIdentifier($record); + $this->generateSearchIdentifiers($record); $this->handleAbstract($record); } @@ -176,8 +176,11 @@ protected function prepareRecord(array &$record) * @param array $record * @return void */ - protected function generateSearchIdentifier(array &$record) + protected function generateSearchIdentifiers(array &$record) { + if (!isset($record['search_document'])) { + $record['search_document_type'] = $this->getDocumentName(); + } if (!isset($record['search_identifier']) && isset($record['uid'])) { $record['search_identifier'] = $this->getDocumentName() . '-' . $record['uid']; } diff --git a/Classes/Domain/Search/CachedSearchService.php b/Classes/Domain/Search/CachedSearchService.php new file mode 100644 index 00000000..76d746b9 --- /dev/null +++ b/Classes/Domain/Search/CachedSearchService.php @@ -0,0 +1,55 @@ +searchService = $searchService; + } + + /** + * @param SearchRequestInterface $searchRequest + * @return SearchResultInterface + */ + public function search(SearchRequestInterface $searchRequest): SearchResultInterface + { + $hash = $this->getHash($searchRequest); + if (isset($this->results[$hash]) && $this->results[$hash] instanceof SearchResultInterface) { + return $this->results[$hash]; + } + return $this->results[$hash] = $this->searchService->search($searchRequest); + } + + /** + * @param SearchRequestInterface $searchRequest + * @return string + */ + protected function getHash(SearchRequestInterface $searchRequest): string + { + if (is_callable([$searchRequest, 'getRequestHash'])) { + return (string)$searchRequest->getRequestHash(); + } + return sha1(serialize($searchRequest)); + } + +} diff --git a/Resources/Private/Partials/Results/ListItem.html b/Resources/Private/Partials/Results/ListItem.html index 7844e324..1ef408b5 100644 --- a/Resources/Private/Partials/Results/ListItem.html +++ b/Resources/Private/Partials/Results/ListItem.html @@ -1,8 +1,8 @@ - - [{result.type}:{result.plainData.uid}] - {result.plainData.search_title} + + [{result.search_document_type}:{result.uid}] - {result.search_title} From 7566bf93d5fc8b10527fa4cdc4426ff903dee1ab Mon Sep 17 00:00:00 2001 From: Benjamin Serfhos Date: Mon, 22 Oct 2018 17:28:17 +0200 Subject: [PATCH 10/73] [FEATURE] Add Frontend User access query for secure search on elastic index --- Classes/Command/IndexCommandController.php | 1 - Classes/Compatibility/TypoScriptService.php | 1 - Classes/Compatibility/TypoScriptService76.php | 1 - Classes/Connection/Elasticsearch.php | 1 - .../Index/TcaIndexer/TcaTableService.php | 2 +- Classes/Domain/Search/CachedSearchService.php | 6 +- .../Search/MissingAttributeException.php | 6 ++ Classes/Domain/Search/QueryFactory.php | 89 ++++++++++--------- .../Hook/Filter/FrontendUserAccessFilter.php | 63 +++++++++++++ Configuration/TCA/Overrides/tt_content.php | 2 - Configuration/TypoScript/setup.typoscript | 13 +++ 11 files changed, 136 insertions(+), 49 deletions(-) create mode 100644 Classes/Domain/Search/MissingAttributeException.php create mode 100644 Classes/Hook/Filter/FrontendUserAccessFilter.php diff --git a/Classes/Command/IndexCommandController.php b/Classes/Command/IndexCommandController.php index d148deeb..e31c50b6 100644 --- a/Classes/Command/IndexCommandController.php +++ b/Classes/Command/IndexCommandController.php @@ -63,7 +63,6 @@ public function indexCommand(string $identifier) $this->outputLine('No indexer found for: ' . $value); } } - } /** diff --git a/Classes/Compatibility/TypoScriptService.php b/Classes/Compatibility/TypoScriptService.php index e5aa7886..14bc3459 100644 --- a/Classes/Compatibility/TypoScriptService.php +++ b/Classes/Compatibility/TypoScriptService.php @@ -27,5 +27,4 @@ */ class TypoScriptService extends CoreTypoScriptService implements TypoScriptServiceInterface { - } diff --git a/Classes/Compatibility/TypoScriptService76.php b/Classes/Compatibility/TypoScriptService76.php index 9df82ea4..395a67a7 100644 --- a/Classes/Compatibility/TypoScriptService76.php +++ b/Classes/Compatibility/TypoScriptService76.php @@ -27,5 +27,4 @@ */ class TypoScriptService76 extends CoreTypoScriptService implements TypoScriptServiceInterface { - } diff --git a/Classes/Connection/Elasticsearch.php b/Classes/Connection/Elasticsearch.php index 98c12f0a..5f07adea 100644 --- a/Classes/Connection/Elasticsearch.php +++ b/Classes/Connection/Elasticsearch.php @@ -26,7 +26,6 @@ use Elastica\Query; use TYPO3\CMS\Core\SingletonInterface as Singleton; use TYPO3\CMS\Extbase\Object\ObjectManagerInterface; -use TYPO3\CMS\Extbase\Utility\DebuggerUtility; /** * Outer wrapper to elasticsearch. diff --git a/Classes/Domain/Index/TcaIndexer/TcaTableService.php b/Classes/Domain/Index/TcaIndexer/TcaTableService.php index 1d6ea901..6b2514c4 100644 --- a/Classes/Domain/Index/TcaIndexer/TcaTableService.php +++ b/Classes/Domain/Index/TcaIndexer/TcaTableService.php @@ -178,7 +178,7 @@ public function prepareRecord(array &$record) true ); // Always fallback on public visibility when configured - $record[$this->tca['ctrl']['enablecolumns']['fe_group']] = !empty($groups) ? $groups : [0]; + $record['search_access'] = !empty($groups) ? $groups : [0]; } if (!isset($record['search_page_typolink'])) { diff --git a/Classes/Domain/Search/CachedSearchService.php b/Classes/Domain/Search/CachedSearchService.php index 76d746b9..b0a6dffe 100644 --- a/Classes/Domain/Search/CachedSearchService.php +++ b/Classes/Domain/Search/CachedSearchService.php @@ -5,7 +5,6 @@ use Codappix\SearchCore\Connection\SearchRequestInterface; use Codappix\SearchCore\Connection\SearchResultInterface; use TYPO3\CMS\Core\SingletonInterface; -use TYPO3\CMS\Extbase\Utility\DebuggerUtility; /** * Service: Cached Search @@ -13,7 +12,11 @@ */ class CachedSearchService implements SingletonInterface { + /** + * @var array + */ protected $results = []; + /** * @var SearchService */ @@ -51,5 +54,4 @@ protected function getHash(SearchRequestInterface $searchRequest): string } return sha1(serialize($searchRequest)); } - } diff --git a/Classes/Domain/Search/MissingAttributeException.php b/Classes/Domain/Search/MissingAttributeException.php new file mode 100644 index 00000000..4754cfe6 --- /dev/null +++ b/Classes/Domain/Search/MissingAttributeException.php @@ -0,0 +1,6 @@ +addSize($searchRequest, $query); $this->addSearch($searchRequest, $query); $this->addBoosts($searchRequest, $query); - $this->addFilter($searchRequest, $query); + $this->addFilters($searchRequest, $query); $this->addFacets($searchRequest, $query); $this->addFields($searchRequest, $query); $this->addSort($searchRequest, $query); @@ -249,67 +249,76 @@ protected function addSort(SearchRequestInterface $searchRequest, array &$query) * @param array $query * @return void */ - protected function addFilter(SearchRequestInterface $searchRequest, array &$query) + protected function addFilters(SearchRequestInterface $searchRequest, array &$query) { if (!$searchRequest->hasFilter()) { return; } - $filter = []; foreach ($searchRequest->getFilter() as $name => $value) { - $filter[] = $this->buildFilter( + $this->addFilter( $name, $value, - $this->configuration->getIfExists('searching.mapping.filter.' . $name) ?: [] + $this->configuration->getIfExists('searching.mapping.filter.' . $name) ?: [], + $query ); } - - ArrayUtility::mergeRecursiveWithOverrule($query, [ - 'query' => [ - 'bool' => [ - 'filter' => $filter, - ], - ], - ]); } /** * @param string $name - * @param $value + * @param string $value * @param array $config + * @param array $query * @return array */ - protected function buildFilter(string $name, $value, array $config): array + protected function addFilter(string $name, $value, array $config, array &$query): array { - if ($config === []) { - return [ - 'term' => [ - $name => $value, - ], - ]; - } - - $filter = []; - - if (isset($config['fields'])) { - foreach ($config['fields'] as $elasticField => $inputField) { - $filter[$elasticField] = $value[$inputField]; + if (!empty($config)) { + if ($config['type'] && $config['type'] === 'user') { + if (!isset($config['userFunc'])) { + throw new MissingAttributeException('No userFunc configured for filter type: user', 1539876182018); + } + + $parameters = [ + 'config' => $config, + 'value' => $value, + 'query' => &$query, + ]; + GeneralUtility::callUserFunction($config['userFunc'], $parameters, $this); + } else { + $filter = []; + if (isset($config['fields'])) { + foreach ($config['fields'] as $elasticField => $inputField) { + $filter[$elasticField] = $value[$inputField]; + } + } + + if (isset($config['raw'])) { + $filter = array_merge($config['raw'], $filter); + } + + if ($config['type'] === 'range') { + $query['query']['bool']['filter'][] = [ + 'range' => [ + $config['field'] => $filter + ] + ]; + } else { + $query['query']['bool']['filter'][] = [ + $config['field'] => $filter + ]; + } } - } - - if (isset($config['raw'])) { - $filter = array_merge($config['raw'], $filter); - } - - if ($config['type'] === 'range') { - return [ - 'range' => [ - $config['field'] => $filter, - ], + } else { + $query['query']['bool']['filter'][] = [ + 'term' => [ + $name => $value + ] ]; } - return [$config['field'] => $filter]; + return $query; } /** diff --git a/Classes/Hook/Filter/FrontendUserAccessFilter.php b/Classes/Hook/Filter/FrontendUserAccessFilter.php new file mode 100644 index 00000000..e043b0a6 --- /dev/null +++ b/Classes/Hook/Filter/FrontendUserAccessFilter.php @@ -0,0 +1,63 @@ +appendQueryWithAccessFilter($parameters['query'], $parameters['value']); + } + + /** + * @param array $query + * @param string $field + */ + protected function appendQueryWithAccessFilter(array &$query, string $field) + { + $query['query']['bool']['must'][] = [ + 'terms' => [$field => $this->getUserGroups()] + ]; + } + + /** + * @return array + */ + protected function getUserGroups(): array + { + $feUser = $this->getFrontendUserAuthentication(); + if ($feUser !== null) { + // If groups is not yet rendered, make sure the group data are fetched + if (!isset($feUser->groupData['uid'])) { + $feUser->fetchGroupData(); + } + + $values = $feUser->groupData['uid']; + if (!empty($values)) { + // Add public content with values + return array_merge([0], $values); + } + } + + // Fallback on public content + return [0]; + } + + /** + * @return FrontendUserAuthentication + */ + protected function getFrontendUserAuthentication() + { + return $GLOBALS['TSFE']->fe_user ?? null; + } +} diff --git a/Configuration/TCA/Overrides/tt_content.php b/Configuration/TCA/Overrides/tt_content.php index 36589eb6..59ad7ede 100644 --- a/Configuration/TCA/Overrides/tt_content.php +++ b/Configuration/TCA/Overrides/tt_content.php @@ -3,7 +3,6 @@ use TYPO3\CMS\Extbase\Utility\ExtensionUtility; call_user_func(function ($extension, $table) { - $plugin = ExtensionUtility::registerPlugin( 'Codappix.' . $extension, 'Results', @@ -21,5 +20,4 @@ ) ?? 'searchcore_form'; $GLOBALS['TCA'][$table]['types']['list']['subtypes_excludelist'][$plugin] = 'recursive,pages'; - }, 'search_core', 'tt_content'); diff --git a/Configuration/TypoScript/setup.typoscript b/Configuration/TypoScript/setup.typoscript index f60ca8d8..981d0336 100644 --- a/Configuration/TypoScript/setup.typoscript +++ b/Configuration/TypoScript/setup.typoscript @@ -39,6 +39,19 @@ plugin.tx_searchcore { # Default query fields (leave empty for all) query = } + + filter { + frontendUserAccess = search_access + } + + mapping { + filter { + frontendUserAccess { + type = user + userFunc = Codappix\SearchCore\Hook\Filter\FrontendUserAccessFilter->generate + } + } + } } } } From 3f5273f0fe2b5ba955ddf04801972cf191f16b95 Mon Sep 17 00:00:00 2001 From: Benjamin Serfhos Date: Mon, 22 Oct 2018 17:28:49 +0200 Subject: [PATCH 11/73] [BUGFIX] Make sure the while loop is not closed when filterRecordsByRootLineBlacklist() returns no results --- Classes/Domain/Index/AbstractIndexer.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Classes/Domain/Index/AbstractIndexer.php b/Classes/Domain/Index/AbstractIndexer.php index 3e3bc55c..5fab1a97 100644 --- a/Classes/Domain/Index/AbstractIndexer.php +++ b/Classes/Domain/Index/AbstractIndexer.php @@ -149,8 +149,10 @@ protected function getRecordGenerator() $offset = 0; $limit = $this->getLimit(); - while (($records = $this->getRecords($offset, $limit)) !== []) { - yield $records; + while (($records = $this->getRecords($offset, $limit)) !== null) { + if (!empty($records)) { + yield $records; + } $offset += $limit; } } From 519bc7e5b4fb8ac6b1ff87a347b78a2ee1d1927c Mon Sep 17 00:00:00 2001 From: Benjamin Serfhos Date: Wed, 24 Oct 2018 10:09:22 +0200 Subject: [PATCH 12/73] [BUGFIX] Inherit access groups from parent pages when extended to subpages --- .../Domain/Index/TcaIndexer/PagesIndexer.php | 46 +++++++++++++++++++ .../Index/TcaIndexer/TcaTableService.php | 3 +- 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/Classes/Domain/Index/TcaIndexer/PagesIndexer.php b/Classes/Domain/Index/TcaIndexer/PagesIndexer.php index ebee56c2..89b2e133 100644 --- a/Classes/Domain/Index/TcaIndexer/PagesIndexer.php +++ b/Classes/Domain/Index/TcaIndexer/PagesIndexer.php @@ -25,6 +25,8 @@ use Codappix\SearchCore\Connection\ConnectionInterface; use Codappix\SearchCore\Domain\Index\TcaIndexer; use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\CMS\Core\Utility\RootlineUtility; +use TYPO3\CMS\Extbase\Object\ObjectManager; /** * Specific indexer for Pages, will basically add content of page. @@ -65,6 +67,9 @@ protected function prepareRecord(array &$record) { parent::prepareRecord($record); + // Override access from parent rootline + $record['search_access'] = $this->fetchAccess($record['uid'], $record['search_access']); + $possibleTitleFields = ['nav_title', 'tx_tqseo_pagetitle_rel', 'title']; foreach ($possibleTitleFields as $searchTitleField) { if (isset($record[$searchTitleField]) && trim($record[$searchTitleField])) { @@ -148,6 +153,47 @@ protected function fetchMediaForPage(int $uid): array return $this->fetchSysFileReferenceUids($uid, 'pages', 'media'); } + /** + * @param integer $uid + * @param array $pageAccess + * @return array + */ + protected function fetchAccess(int $uid, array $pageAccess): array + { + try { + $objectManager = GeneralUtility::makeInstance(ObjectManager::class); + $rootline = $objectManager->get(RootlineUtility::class, $uid)->get(); + } catch (\RuntimeException $e) { + $this->logger->notice( + sprintf('Could not fetch rootline for page %u, because: %s', $uid, $e->getMessage()), + [$pageAccess, $e] + ); + return $pageAccess; + } + + $access = [$pageAccess]; + $extended = false; + foreach ($rootline as $pageInRootLine) { + if ($pageInRootLine['extendToSubpages'] && (!empty($pageInRootLine['fe_group']))) { + $extended = true; + $access[] = GeneralUtility::intExplode( + ',', + $pageInRootLine['fe_group'], + true + ); + } + } + + // Return combined rootline extended access and return unique id's + $access = array_unique(array_merge(...$access)); + + // Remove public value if fe_group is extended to this page + if ($extended && ($key = array_search(0, $access, true)) !== false) { + unset($access[$key]); + } + return array_values($access); + } + /** * @param integer $uid * @param string $tablename diff --git a/Classes/Domain/Index/TcaIndexer/TcaTableService.php b/Classes/Domain/Index/TcaIndexer/TcaTableService.php index 6b2514c4..2125a73b 100644 --- a/Classes/Domain/Index/TcaIndexer/TcaTableService.php +++ b/Classes/Domain/Index/TcaIndexer/TcaTableService.php @@ -171,7 +171,8 @@ public function prepareRecord(array &$record) if (isset($record[$this->tca['ctrl']['label']]) && !isset($record['search_title'])) { $record['search_title'] = $record[$this->tca['ctrl']['label']]; } - if (isset($this->tca['ctrl']['enablecolumns']['fe_group']) && isset($record[$this->tca['ctrl']['enablecolumns']['fe_group']])) { + + if (isset($this->tca['ctrl']['enablecolumns']['fe_group'], $record[$this->tca['ctrl']['enablecolumns']['fe_group']])) { $groups = GeneralUtility::intExplode( ',', $record[$this->tca['ctrl']['enablecolumns']['fe_group']], From 028914e7899da245668fe3bf817b73b0a837d52f Mon Sep 17 00:00:00 2001 From: Benjamin Serfhos Date: Wed, 24 Oct 2018 14:08:59 +0200 Subject: [PATCH 13/73] [TASK] Finetune query for document_type instead of regex --- Classes/Domain/Index/AbstractIndexer.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Classes/Domain/Index/AbstractIndexer.php b/Classes/Domain/Index/AbstractIndexer.php index 5fab1a97..ddaa54a3 100644 --- a/Classes/Domain/Index/AbstractIndexer.php +++ b/Classes/Domain/Index/AbstractIndexer.php @@ -133,8 +133,8 @@ public function delete() $this->logger->info('Start deletion of index.'); $this->connection->deleteIndexByQuery(Query::create([ 'query' => [ - 'regexp' => [ - 'search_identifier' => $this->getDocumentName() . '-*' + 'term' => [ + 'search_document_type' => $this->getDocumentName() ] ] ])); From a50cbf25a2c2b29f08536ac455301f915ca91acc Mon Sep 17 00:00:00 2001 From: Benjamin Serfhos Date: Wed, 24 Oct 2018 17:41:47 +0200 Subject: [PATCH 14/73] [TASK] Process feedback and fix unit-tests --- .../Elasticsearch/MappingFactory.php | 4 --- Classes/Domain/Model/SearchRequest.php | 3 +- Classes/Domain/Search/QueryFactory.php | 6 ++-- Classes/Utility/ArrayUtility.php | 35 +++++++++++++++++++ .../Elasticsearch/MappingFactoryTest.php | 14 +------- .../Unit/Controller/SearchControllerTest.php | 4 +-- .../Unit/Domain/Index/AbstractIndexerTest.php | 2 ++ Tests/Unit/Domain/Model/SearchRequestTest.php | 4 +++ Tests/Unit/Domain/Search/QueryFactoryTest.php | 6 ++-- 9 files changed, 54 insertions(+), 24 deletions(-) create mode 100644 Classes/Utility/ArrayUtility.php diff --git a/Classes/Connection/Elasticsearch/MappingFactory.php b/Classes/Connection/Elasticsearch/MappingFactory.php index 9f1f262d..705f58f8 100644 --- a/Classes/Connection/Elasticsearch/MappingFactory.php +++ b/Classes/Connection/Elasticsearch/MappingFactory.php @@ -55,10 +55,6 @@ public function getMapping(\Elastica\Type $type): \Elastica\Type\Mapping $mapping->setType($type); $configuration = $this->getConfiguration($type->getName()); - if (isset($configuration['_all'])) { - $mapping->setAllField($configuration['_all']); - unset($configuration['_all']); - } $mapping->setProperties($configuration); return $mapping; diff --git a/Classes/Domain/Model/SearchRequest.php b/Classes/Domain/Model/SearchRequest.php index 0c66365d..787a936f 100644 --- a/Classes/Domain/Model/SearchRequest.php +++ b/Classes/Domain/Model/SearchRequest.php @@ -25,6 +25,7 @@ use Codappix\SearchCore\Connection\FacetRequestInterface; use Codappix\SearchCore\Connection\SearchRequestInterface; use Codappix\SearchCore\Domain\Search\SearchService; +use Codappix\SearchCore\Utility\ArrayUtility as CustomArrayUtility; use TYPO3\CMS\Core\Utility\ArrayUtility; /** @@ -101,7 +102,7 @@ public function getSearchTerm(): string public function setFilter(array $filter) { $filter = ArrayUtility::removeArrayEntryByValue($filter, ''); - $this->filter = ArrayUtility::removeNullValuesRecursive($filter); + $this->filter = CustomArrayUtility::removeEmptyElementsRecursively($filter); } /** diff --git a/Classes/Domain/Search/QueryFactory.php b/Classes/Domain/Search/QueryFactory.php index 4bbd22d1..c2975608 100644 --- a/Classes/Domain/Search/QueryFactory.php +++ b/Classes/Domain/Search/QueryFactory.php @@ -124,9 +124,11 @@ protected function addSearch(SearchRequestInterface $searchRequest, array &$quer 'query' => $searchRequest->getSearchTerm(), ]; - $fieldsToQuery = GeneralUtility::trimExplode(',', $this->configuration->getIfExists('searching.fields.query'), true); - if (!empty($fieldsToQuery)) { + try { + $fieldsToQuery = GeneralUtility::trimExplode(',', $this->configuration->get('searching.fields.query'), true); $matchExpression['fields'] = $fieldsToQuery; + } catch (InvalidArgumentException $e) { + // Nothing configured } $minimumShouldMatch = $this->configuration->getIfExists('searching.minimumShouldMatch'); diff --git a/Classes/Utility/ArrayUtility.php b/Classes/Utility/ArrayUtility.php new file mode 100644 index 00000000..facc6fdb --- /dev/null +++ b/Classes/Utility/ArrayUtility.php @@ -0,0 +1,35 @@ + $value) { + if (is_array($value)) { + $result[$key] = self::removeEmptyElementsRecursively($value); + if ($result[$key] === []) { + unset($result[$key]); + } + } elseif ($value === null) { + unset($result[$key]); + } + } + return $result; + } + +} diff --git a/Tests/Unit/Connection/Elasticsearch/MappingFactoryTest.php b/Tests/Unit/Connection/Elasticsearch/MappingFactoryTest.php index 8dde1cbf..094c5d09 100644 --- a/Tests/Unit/Connection/Elasticsearch/MappingFactoryTest.php +++ b/Tests/Unit/Connection/Elasticsearch/MappingFactoryTest.php @@ -46,10 +46,6 @@ public function typoScriptConfigurationIsProvidedToIndex() { $indexName = 'someIndex'; $configuration = [ - '_all' => [ - 'type' => 'text', - 'analyzer' => 'ngram4', - ], 'channel' => [ 'type' => 'keyword', ], @@ -64,16 +60,8 @@ public function typoScriptConfigurationIsProvidedToIndex() ->method('get') ->with('indexing.' . $indexName . '.mapping') ->willReturn($configuration); - $mapping = $this->subject->getMapping($type)->toArray()[$indexName]; - $this->assertArraySubset( - [ - '_all' => $configuration['_all'] - ], - $mapping, - true, - 'Configuration of _all field was not set for mapping.' - ); + $this->assertArraySubset( [ 'channel' => $configuration['channel'] diff --git a/Tests/Unit/Controller/SearchControllerTest.php b/Tests/Unit/Controller/SearchControllerTest.php index 67c6d98f..8617f6c2 100644 --- a/Tests/Unit/Controller/SearchControllerTest.php +++ b/Tests/Unit/Controller/SearchControllerTest.php @@ -22,7 +22,7 @@ use Codappix\SearchCore\Controller\SearchController; use Codappix\SearchCore\Domain\Model\SearchRequest; -use Codappix\SearchCore\Domain\Search\SearchService; +use Codappix\SearchCore\Domain\Search\CachedSearchService; use Codappix\SearchCore\Tests\Unit\AbstractUnitTestCase; use TYPO3\CMS\Extbase\Mvc\Web\Request; use TYPO3\CMS\Extbase\Object\ObjectManager; @@ -54,7 +54,7 @@ public function setUp() parent::setUp(); - $searchService = $this->getMockBuilder(SearchService::class) + $searchService = $this->getMockBuilder(CachedSearchService::class) ->disableOriginalConstructor() ->getMock(); $this->request = new Request(); diff --git a/Tests/Unit/Domain/Index/AbstractIndexerTest.php b/Tests/Unit/Domain/Index/AbstractIndexerTest.php index 411cc24e..b7373da5 100644 --- a/Tests/Unit/Domain/Index/AbstractIndexerTest.php +++ b/Tests/Unit/Domain/Index/AbstractIndexerTest.php @@ -82,6 +82,7 @@ public function executesConfiguredDataProcessingWithConfiguration() $expectedRecord['new_test_field'] = 'test'; $expectedRecord['new_test_field2'] = 'test' . PHP_EOL . 'test'; $expectedRecord['search_abstract'] = ''; + $expectedRecord['search_document_type'] = 'testTable'; $this->dataProcessorService->expects($this->any()) ->method('executeDataProcessor') @@ -137,6 +138,7 @@ public function executesNoDataProcessingForMissingConfiguration() $record = ['field 1' => 'test']; $expectedRecord = $record; $expectedRecord['search_abstract'] = ''; + $expectedRecord['search_document_type'] = 'testTable'; $this->configuration->expects($this->exactly(2)) ->method('get') diff --git a/Tests/Unit/Domain/Model/SearchRequestTest.php b/Tests/Unit/Domain/Model/SearchRequestTest.php index 25ced4e0..fee7a807 100644 --- a/Tests/Unit/Domain/Model/SearchRequestTest.php +++ b/Tests/Unit/Domain/Model/SearchRequestTest.php @@ -45,6 +45,10 @@ public function emptyFilterWillNotBeSet(array $filter) ); } + /** + * Data provider for emptyFilterWillNotBeSet() + * @return array + */ public function possibleEmptyFilter() { return [ diff --git a/Tests/Unit/Domain/Search/QueryFactoryTest.php b/Tests/Unit/Domain/Search/QueryFactoryTest.php index dc824c5f..5603502c 100644 --- a/Tests/Unit/Domain/Search/QueryFactoryTest.php +++ b/Tests/Unit/Domain/Search/QueryFactoryTest.php @@ -428,7 +428,7 @@ public function configuredQueryFieldsAreAddedToQuery() ['searching.fieldValueFactor'] ) ->will($this->onConsecutiveCalls( - '_all, field1, field2', + 'field1, field2', $this->throwException(new InvalidArgumentException), $this->throwException(new InvalidArgumentException), $this->throwException(new InvalidArgumentException), @@ -445,7 +445,6 @@ public function configuredQueryFieldsAreAddedToQuery() 'type' => 'most_fields', 'query' => 'SearchWord', 'fields' => [ - '_all', 'field1', 'field2', ], @@ -662,6 +661,9 @@ public function sortIsNotAddedToQuery() ); } + /** + * @return void + */ protected function configureConfigurationMockWithDefault() { $this->configuration->expects($this->any()) From 628f76af4bf9f0cea0bbdd556f754ac9088382f0 Mon Sep 17 00:00:00 2001 From: Benjamin Serfhos Date: Wed, 24 Oct 2018 17:57:16 +0200 Subject: [PATCH 15/73] [BUGFIX] Use relative location of Fixtures --- Tests/Functional/AbstractFunctionalTestCase.php | 2 +- Tests/Functional/Connection/Elasticsearch/FacetTest.php | 2 +- Tests/Functional/Connection/Elasticsearch/FilterTest.php | 2 +- .../Connection/Elasticsearch/IndexTcaTableTest.php | 6 +++--- .../DataProcessing/TcaRelationResolvingProcessorTest.php | 8 ++++---- .../Functional/Hooks/DataHandler/NonAllowedTablesTest.php | 2 +- .../NonAllowedTablesWithMultipleTablesConfiguredTest.php | 2 +- .../Hooks/DataHandler/ProcessesAllowedTablesTest.php | 2 +- Tests/Functional/Indexing/PagesIndexerTest.php | 8 ++++---- Tests/Functional/Indexing/TcaIndexerTest.php | 2 +- 10 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Tests/Functional/AbstractFunctionalTestCase.php b/Tests/Functional/AbstractFunctionalTestCase.php index d0154576..717acc85 100644 --- a/Tests/Functional/AbstractFunctionalTestCase.php +++ b/Tests/Functional/AbstractFunctionalTestCase.php @@ -52,7 +52,7 @@ public function setUp() */ protected function getDataSets() { - return ['Tests/Functional/Fixtures/BasicSetup.xml']; + return ['EXT:search_core/Tests/Functional/Fixtures/BasicSetup.xml']; } /** diff --git a/Tests/Functional/Connection/Elasticsearch/FacetTest.php b/Tests/Functional/Connection/Elasticsearch/FacetTest.php index 1c38c073..a43a05e0 100644 --- a/Tests/Functional/Connection/Elasticsearch/FacetTest.php +++ b/Tests/Functional/Connection/Elasticsearch/FacetTest.php @@ -39,7 +39,7 @@ protected function getDataSets() { return array_merge( parent::getDataSets(), - ['Tests/Functional/Fixtures/Searching/Filter.xml'] + ['EXT:search_core/Tests/Functional/Fixtures/Searching/Filter.xml'] ); } diff --git a/Tests/Functional/Connection/Elasticsearch/FilterTest.php b/Tests/Functional/Connection/Elasticsearch/FilterTest.php index 894fb3f6..588aed39 100644 --- a/Tests/Functional/Connection/Elasticsearch/FilterTest.php +++ b/Tests/Functional/Connection/Elasticsearch/FilterTest.php @@ -31,7 +31,7 @@ protected function getDataSets() { return array_merge( parent::getDataSets(), - ['Tests/Functional/Fixtures/Searching/Filter.xml'] + ['EXT:search_core/Tests/Functional/Fixtures/Searching/Filter.xml'] ); } diff --git a/Tests/Functional/Connection/Elasticsearch/IndexTcaTableTest.php b/Tests/Functional/Connection/Elasticsearch/IndexTcaTableTest.php index ae671dda..e3614fd4 100644 --- a/Tests/Functional/Connection/Elasticsearch/IndexTcaTableTest.php +++ b/Tests/Functional/Connection/Elasticsearch/IndexTcaTableTest.php @@ -32,7 +32,7 @@ protected function getDataSets() { return array_merge( parent::getDataSets(), - ['Tests/Functional/Fixtures/Indexing/IndexTcaTable.xml'] + ['EXT:search_core/Tests/Functional/Fixtures/Indexing/IndexTcaTable.xml'] ); } @@ -124,7 +124,7 @@ public function indexingRespectsUserWhereClause() parent::getTypoScriptFilesForFrontendRootPage(), ['EXT:search_core/Tests/Functional/Fixtures/Indexing/UserWhereClause.ts'] )); - $this->importDataSet('Tests/Functional/Fixtures/Indexing/UserWhereClause.xml'); + $this->importDataSet('EXT:search_core/Tests/Functional/Fixtures/Indexing/UserWhereClause.xml'); \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(ObjectManager::class) ->get(IndexerFactory::class) @@ -157,7 +157,7 @@ public function indexingRespectsUserWhereClause() */ public function resolvesRelations() { - $this->importDataSet('Tests/Functional/Fixtures/Indexing/ResolveRelations.xml'); + $this->importDataSet('EXT:search_core/Tests/Functional/Fixtures/Indexing/ResolveRelations.xml'); \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(ObjectManager::class) ->get(IndexerFactory::class) diff --git a/Tests/Functional/DataProcessing/TcaRelationResolvingProcessorTest.php b/Tests/Functional/DataProcessing/TcaRelationResolvingProcessorTest.php index c5011df9..28f2854e 100644 --- a/Tests/Functional/DataProcessing/TcaRelationResolvingProcessorTest.php +++ b/Tests/Functional/DataProcessing/TcaRelationResolvingProcessorTest.php @@ -33,7 +33,7 @@ class TcaRelationResolvingProcessorTest extends AbstractFunctionalTestCase */ public function resolveInlineRelation() { - $this->importDataSet('Tests/Functional/Fixtures/Indexing/TcaIndexer/RelationResolver/InlineRelation.xml'); + $this->importDataSet('EXT:search_core/Tests/Functional/Fixtures/Indexing/TcaIndexer/RelationResolver/InlineRelation.xml'); $objectManager = GeneralUtility::makeInstance(ObjectManager::class); $table = 'sys_file'; @@ -55,7 +55,7 @@ public function resolveInlineRelation() */ public function resolveStaticSelectItems() { - $this->importDataSet('Tests/Functional/Fixtures/Indexing/TcaIndexer/RelationResolver/StaticSelectItems.xml'); + $this->importDataSet('EXT:search_core/Tests/Functional/Fixtures/Indexing/TcaIndexer/RelationResolver/StaticSelectItems.xml'); $objectManager = GeneralUtility::makeInstance(ObjectManager::class); $table = 'tt_content'; @@ -74,7 +74,7 @@ public function resolveStaticSelectItems() */ public function resolveForeignDb() { - $this->importDataSet('Tests/Functional/Fixtures/Indexing/TcaIndexer/RelationResolver/ForeignDb.xml'); + $this->importDataSet('EXT:search_core/Tests/Functional/Fixtures/Indexing/TcaIndexer/RelationResolver/ForeignDb.xml'); $objectManager = GeneralUtility::makeInstance(ObjectManager::class); $table = 'tt_content'; @@ -96,7 +96,7 @@ public function resolveForeignDb() */ public function resolveForeignMmSelect() { - $this->importDataSet('Tests/Functional/Fixtures/Indexing/TcaIndexer/RelationResolver/ForeignMmSelect.xml'); + $this->importDataSet('EXT:search_core/Tests/Functional/Fixtures/Indexing/TcaIndexer/RelationResolver/ForeignMmSelect.xml'); $objectManager = GeneralUtility::makeInstance(ObjectManager::class); $table = 'tt_content'; diff --git a/Tests/Functional/Hooks/DataHandler/NonAllowedTablesTest.php b/Tests/Functional/Hooks/DataHandler/NonAllowedTablesTest.php index a9cbaae4..3c9390ac 100644 --- a/Tests/Functional/Hooks/DataHandler/NonAllowedTablesTest.php +++ b/Tests/Functional/Hooks/DataHandler/NonAllowedTablesTest.php @@ -38,7 +38,7 @@ protected function getDataSets() { return array_merge( parent::getDataSets(), - ['Tests/Functional/Fixtures/Hooks/DataHandler/NonAllowedTables.xml'] + ['EXT:search_core/Tests/Functional/Fixtures/Hooks/DataHandler/NonAllowedTables.xml'] ); } diff --git a/Tests/Functional/Hooks/DataHandler/NonAllowedTablesWithMultipleTablesConfiguredTest.php b/Tests/Functional/Hooks/DataHandler/NonAllowedTablesWithMultipleTablesConfiguredTest.php index d04d416d..c88766e0 100644 --- a/Tests/Functional/Hooks/DataHandler/NonAllowedTablesWithMultipleTablesConfiguredTest.php +++ b/Tests/Functional/Hooks/DataHandler/NonAllowedTablesWithMultipleTablesConfiguredTest.php @@ -26,7 +26,7 @@ protected function getTypoScriptFilesForFrontendRootPage() { return array_merge( parent::getTypoScriptFilesForFrontendRootPage(), - ['EXT:search_core/Tests/Functional/Fixtures/Hooks/DataHandler/MultipleAllowedTables.ts'] + ['EXT:search_core/EXT:search_core/Tests/Functional/Fixtures/Hooks/DataHandler/MultipleAllowedTables.ts'] ); } } diff --git a/Tests/Functional/Hooks/DataHandler/ProcessesAllowedTablesTest.php b/Tests/Functional/Hooks/DataHandler/ProcessesAllowedTablesTest.php index 5a571d39..5e9abe57 100644 --- a/Tests/Functional/Hooks/DataHandler/ProcessesAllowedTablesTest.php +++ b/Tests/Functional/Hooks/DataHandler/ProcessesAllowedTablesTest.php @@ -38,7 +38,7 @@ protected function getDataSets() { return array_merge( parent::getDataSets(), - ['Tests/Functional/Fixtures/Hooks/DataHandler/AllowedTables.xml'] + ['EXT:search_core/Tests/Functional/Fixtures/Hooks/DataHandler/AllowedTables.xml'] ); } diff --git a/Tests/Functional/Indexing/PagesIndexerTest.php b/Tests/Functional/Indexing/PagesIndexerTest.php index 3ac91f44..70aac44b 100644 --- a/Tests/Functional/Indexing/PagesIndexerTest.php +++ b/Tests/Functional/Indexing/PagesIndexerTest.php @@ -33,7 +33,7 @@ class PagesIndexerTest extends AbstractFunctionalTestCase */ public function pagesContainAllAdditionalInformation() { - $this->importDataSet('Tests/Functional/Fixtures/Indexing/IndexTcaTable.xml'); + $this->importDataSet('EXT:search_core/Tests/Functional/Fixtures/Indexing/IndexTcaTable.xml'); $objectManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(ObjectManager::class); $tableName = 'pages'; @@ -100,9 +100,9 @@ public function rootLineIsRespectedDuringIndexing($dataSetPath) 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'], + 'Broken root line' => ['EXT:search_core/Tests/Functional/Fixtures/Indexing/PagesIndexer/BrokenRootLine.xml'], + 'Recycler doktype' => ['EXT:search_core/Tests/Functional/Fixtures/Indexing/PagesIndexer/Recycler.xml'], + 'Extended timing to sub pages' => ['EXT:search_core/Tests/Functional/Fixtures/Indexing/PagesIndexer/InheritedTiming.xml'], ]; } } diff --git a/Tests/Functional/Indexing/TcaIndexerTest.php b/Tests/Functional/Indexing/TcaIndexerTest.php index 472cc154..b447c994 100644 --- a/Tests/Functional/Indexing/TcaIndexerTest.php +++ b/Tests/Functional/Indexing/TcaIndexerTest.php @@ -43,7 +43,7 @@ protected function getTypoScriptFilesForFrontendRootPage() */ public function respectRootLineBlacklist() { - $this->importDataSet('Tests/Functional/Fixtures/Indexing/TcaIndexer/RespectRootLineBlacklist.xml'); + $this->importDataSet('EXT:search_core/Tests/Functional/Fixtures/Indexing/TcaIndexer/RespectRootLineBlacklist.xml'); $objectManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(ObjectManager::class); $tableName = 'tt_content'; $tableService = $objectManager->get( From b70dd604fec77828f5fd12ed09d37fd41984c374 Mon Sep 17 00:00:00 2001 From: Benjamin Serfhos Date: Thu, 25 Oct 2018 14:01:57 +0200 Subject: [PATCH 16/73] [TASK] Process own feedback based on tests --- Classes/Command/IndexCommandController.php | 2 +- .../ImplementationRegistrationService.php | 1 + Classes/Compatibility/TypoScriptService.php | 1 + Classes/Compatibility/TypoScriptService76.php | 1 + .../TypoScriptServiceInterface.php | 1 + Classes/Connection/Elasticsearch.php | 9 +-- .../Elasticsearch/MappingFactory.php | 5 +- Classes/Domain/Index/AbstractIndexer.php | 20 +++++- Classes/Domain/Index/IndexerInterface.php | 7 ++ Classes/Domain/Index/TcaIndexer.php | 10 ++- .../Domain/Index/TcaIndexer/PagesIndexer.php | 2 +- .../Index/TcaIndexer/RelationResolver.php | 15 +++-- .../Index/TcaIndexer/TcaTableService.php | 3 + .../Search/MissingAttributeException.php | 1 + Classes/Utility/ArrayUtility.php | 1 - .../Functional/AbstractFunctionalTestCase.php | 3 +- .../AbstractFunctionalTestCase.php | 1 + .../Connection/Elasticsearch/FacetTest.php | 10 ++- .../Connection/Elasticsearch/FilterTest.php | 6 +- .../Elasticsearch/IndexDeletionTest.php | 4 +- .../Elasticsearch/IndexTcaTableTest.php | 64 ++++++++++--------- ...bjectDataProcessorAdapterProcessorTest.php | 3 +- .../TcaRelationResolvingProcessorTest.php | 1 + Tests/Functional/Fixtures/BasicSetup.ts | 6 -- Tests/Functional/FunctionalTests.xml | 26 ++++---- .../DataHandler/AbstractDataHandlerTest.php | 5 +- .../DataHandler/NonAllowedTablesTest.php | 4 +- ...TablesWithMultipleTablesConfiguredTest.php | 1 + .../ProcessesAllowedTablesTest.php | 16 ++--- ...TablesWithMultipleTablesConfiguredTest.php | 1 + .../Functional/Indexing/PagesIndexerTest.php | 5 +- Tests/Functional/Indexing/TcaIndexerTest.php | 3 +- Tests/Unit/AbstractUnitTestCase.php | 5 +- .../Command/IndexCommandControllerTest.php | 3 +- .../ConfigurationUtilityTest.php | 5 +- .../Elasticsearch/FacetOptionTest.php | 1 + .../Elasticsearch/IndexFactoryTest.php | 1 + .../Elasticsearch/MappingFactoryTest.php | 1 + .../Unit/Controller/SearchControllerTest.php | 1 + .../DataProcessing/CopyToProcessorTest.php | 1 + .../DataProcessing/GeoPointProcessorTest.php | 1 + .../DataProcessing/RemoveProcessorTest.php | 1 + .../TcaRelationResolvingProcessorTest.php | 3 +- .../Unit/Domain/Index/AbstractIndexerTest.php | 7 +- .../Index/TcaIndexer/TcaTableServiceTest.php | 4 +- Tests/Unit/Domain/Model/ResultItemTest.php | 1 + Tests/Unit/Domain/Model/SearchRequestTest.php | 1 + Tests/Unit/Domain/Model/SearchResultTest.php | 1 + Tests/Unit/Domain/Search/QueryFactoryTest.php | 12 +--- .../Unit/Domain/Search/SearchServiceTest.php | 7 +- Tests/Unit/Hook/DataHandlerTest.php | 6 +- .../Form/Finisher/DataHandlerFinisherTest.php | 5 +- Tests/Unit/UnitTests.xml | 26 ++++---- 53 files changed, 191 insertions(+), 140 deletions(-) diff --git a/Classes/Command/IndexCommandController.php b/Classes/Command/IndexCommandController.php index e31c50b6..f558f40d 100644 --- a/Classes/Command/IndexCommandController.php +++ b/Classes/Command/IndexCommandController.php @@ -77,7 +77,7 @@ public function deleteCommand(string $identifier) $identifiers = GeneralUtility::trimExplode(',', $identifier, true); foreach ($identifiers as $value) { try { - $this->indexerFactory->getIndexer($value)->delete(); + $this->indexerFactory->getIndexer($value)->deleteDocuments(); $this->outputLine($value . ' was deleted.'); } catch (NoMatchingIndexerException $e) { $this->outputLine('No indexer found for: ' . $value); diff --git a/Classes/Compatibility/ImplementationRegistrationService.php b/Classes/Compatibility/ImplementationRegistrationService.php index fa3faa83..46aa3f0f 100644 --- a/Classes/Compatibility/ImplementationRegistrationService.php +++ b/Classes/Compatibility/ImplementationRegistrationService.php @@ -1,4 +1,5 @@ getType(); + $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(); + $this->mappingFactory->getMapping($type, $documentType)->send(); $callback($type); $type->getIndex()->refresh(); } @@ -249,14 +249,15 @@ public function search(SearchRequestInterface $searchRequest): SearchResultInter } /** + * @param string $documentType * @return \Elastica\Type */ - protected function getType(): \Elastica\Type + protected function getType($documentType): \Elastica\Type { return $this->typeFactory->getType( $this->indexFactory->getIndex( $this->connection, - 'document' + $documentType ), 'document' ); diff --git a/Classes/Connection/Elasticsearch/MappingFactory.php b/Classes/Connection/Elasticsearch/MappingFactory.php index 705f58f8..5579cd2e 100644 --- a/Classes/Connection/Elasticsearch/MappingFactory.php +++ b/Classes/Connection/Elasticsearch/MappingFactory.php @@ -47,14 +47,15 @@ public function __construct(ConfigurationContainerInterface $configuration) * Get an mapping based on type. * * @param \Elastica\Type $type + * @param string $documentType * @return \Elastica\Type\Mapping */ - public function getMapping(\Elastica\Type $type): \Elastica\Type\Mapping + public function getMapping(\Elastica\Type $type, $documentType = null): \Elastica\Type\Mapping { $mapping = new \Elastica\Type\Mapping(); $mapping->setType($type); - $configuration = $this->getConfiguration($type->getName()); + $configuration = $this->getConfiguration($documentType ?? $type->getName()); $mapping->setProperties($configuration); return $mapping; diff --git a/Classes/Domain/Index/AbstractIndexer.php b/Classes/Domain/Index/AbstractIndexer.php index ddaa54a3..e29ff75a 100644 --- a/Classes/Domain/Index/AbstractIndexer.php +++ b/Classes/Domain/Index/AbstractIndexer.php @@ -120,7 +120,7 @@ public function indexDocument(string $identifier) $this->connection->addDocument($this->getDocumentName(), $record); } catch (NoRecordFoundException $e) { $this->logger->info('Could not index document. Try to delete it therefore.', [$e->getMessage()]); - $this->connection->deleteDocument($this->getDocumentName(), $identifier); + $this->connection->deleteDocument($this->getDocumentName(), $this->getIdentifier($identifier)); } $this->logger->info('Finish indexing'); } @@ -131,6 +131,16 @@ public function indexDocument(string $identifier) public function delete() { $this->logger->info('Start deletion of index.'); + $this->connection->deleteIndex(); + $this->logger->info('Finish deletion.'); + } + + /** + * @return void + */ + public function deleteDocuments() + { + $this->logger->info('Start deletion of indexed documents.'); $this->connection->deleteIndexByQuery(Query::create([ 'query' => [ 'term' => [ @@ -184,7 +194,7 @@ protected function generateSearchIdentifiers(array &$record) $record['search_document_type'] = $this->getDocumentName(); } if (!isset($record['search_identifier']) && isset($record['uid'])) { - $record['search_identifier'] = $this->getDocumentName() . '-' . $record['uid']; + $record['search_identifier'] = $this->getIdentifier($record['uid']); } } @@ -244,4 +254,10 @@ abstract protected function getRecord(int $identifier): array; * @return string */ abstract protected function getDocumentName(): string; + + /** + * @param string $identifier + * @return string + */ + abstract public function getIdentifier($identifier): string; } diff --git a/Classes/Domain/Index/IndexerInterface.php b/Classes/Domain/Index/IndexerInterface.php index cd9ad53c..ace52433 100644 --- a/Classes/Domain/Index/IndexerInterface.php +++ b/Classes/Domain/Index/IndexerInterface.php @@ -55,4 +55,11 @@ public function setIdentifier(string $identifier); * @return void */ public function delete(); + + /** + * Delete the whole index. + * + * @return void + */ + public function deleteDocuments(); } diff --git a/Classes/Domain/Index/TcaIndexer.php b/Classes/Domain/Index/TcaIndexer.php index 4ae11173..74141d02 100644 --- a/Classes/Domain/Index/TcaIndexer.php +++ b/Classes/Domain/Index/TcaIndexer.php @@ -77,7 +77,6 @@ protected function getRecords(int $offset, int $limit) protected function getRecord(int $identifier): array { $record = $this->tcaTableService->getRecord($identifier); - if ($record === []) { throw new NoRecordFoundException( 'Record could not be fetched from database: "' . $identifier . '". Perhaps record is not active.', @@ -96,4 +95,13 @@ protected function getDocumentName(): string { return $this->tcaTableService->getTableName(); } + + /** + * @param string $identifier + * @return string + */ + public function getIdentifier($identifier): string + { + return $this->getDocumentName() . '-' . $identifier; + } } diff --git a/Classes/Domain/Index/TcaIndexer/PagesIndexer.php b/Classes/Domain/Index/TcaIndexer/PagesIndexer.php index 89b2e133..20ccc65c 100644 --- a/Classes/Domain/Index/TcaIndexer/PagesIndexer.php +++ b/Classes/Domain/Index/TcaIndexer/PagesIndexer.php @@ -68,7 +68,7 @@ protected function prepareRecord(array &$record) parent::prepareRecord($record); // Override access from parent rootline - $record['search_access'] = $this->fetchAccess($record['uid'], $record['search_access']); + $record['search_access'] = $this->fetchAccess($record['uid'], (array)$record['search_access']); $possibleTitleFields = ['nav_title', 'tx_tqseo_pagetitle_rel', 'title']; foreach ($possibleTitleFields as $searchTitleField) { diff --git a/Classes/Domain/Index/TcaIndexer/RelationResolver.php b/Classes/Domain/Index/TcaIndexer/RelationResolver.php index db23b4d6..7a4ac2f5 100644 --- a/Classes/Domain/Index/TcaIndexer/RelationResolver.php +++ b/Classes/Domain/Index/TcaIndexer/RelationResolver.php @@ -135,12 +135,13 @@ protected function getUtilityForMode(): string protected function getColumnValue(array $record, string $column, TcaTableServiceInterface $service): string { $utility = GeneralUtility::makeInstance($this->getUtilityForMode()); - return $utility::getProcessedValueExtra( - $service->getTableName(), - $column, - $record[$column], - 0, - $record['uid'] - ) ?? ''; + $value = $value = $utility::getProcessedValueExtra( + $service->getTableName(), + $column, + $record[$column], + 0, + $record['uid'] + ); + return $value ? (string)$value : ''; } } diff --git a/Classes/Domain/Index/TcaIndexer/TcaTableService.php b/Classes/Domain/Index/TcaIndexer/TcaTableService.php index 2125a73b..c390d370 100644 --- a/Classes/Domain/Index/TcaIndexer/TcaTableService.php +++ b/Classes/Domain/Index/TcaIndexer/TcaTableService.php @@ -187,6 +187,9 @@ public function prepareRecord(array &$record) case 'pages': $record['search_page_typolink'] = 't3://page?uid=' . $record['uid']; break; + case 'tt_content': + $record['search_page_typolink'] = 't3://page?uid=' . $record['pid'] . '#' . $record['uid']; + break; case 'sys_file': $record['search_page_typolink'] = 't3://file?uid=' . $record['uid']; break; diff --git a/Classes/Domain/Search/MissingAttributeException.php b/Classes/Domain/Search/MissingAttributeException.php index 4754cfe6..0e075ed7 100644 --- a/Classes/Domain/Search/MissingAttributeException.php +++ b/Classes/Domain/Search/MissingAttributeException.php @@ -1,4 +1,5 @@ get(IndexerFactory::class) ->getIndexer('tt_content') - ->indexAllDocuments() - ; + ->indexAllDocuments(); $searchService = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(ObjectManager::class) ->get(SearchService::class); diff --git a/Tests/Functional/Connection/Elasticsearch/FilterTest.php b/Tests/Functional/Connection/Elasticsearch/FilterTest.php index 588aed39..2a93f1c5 100644 --- a/Tests/Functional/Connection/Elasticsearch/FilterTest.php +++ b/Tests/Functional/Connection/Elasticsearch/FilterTest.php @@ -1,4 +1,5 @@ get(IndexerFactory::class) ->getIndexer('tt_content') - ->indexAllDocuments() - ; + ->indexAllDocuments(); $searchService = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(ObjectManager::class) ->get(SearchService::class); @@ -55,7 +55,7 @@ public function itsPossibleToFilterResultsByASingleField() $searchRequest->setFilter(['CType' => 'HTML']); $result = $searchService->search($searchRequest); - $this->assertSame(5, (int) $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.'); } } diff --git a/Tests/Functional/Connection/Elasticsearch/IndexDeletionTest.php b/Tests/Functional/Connection/Elasticsearch/IndexDeletionTest.php index 8297a2af..9e6fb029 100644 --- a/Tests/Functional/Connection/Elasticsearch/IndexDeletionTest.php +++ b/Tests/Functional/Connection/Elasticsearch/IndexDeletionTest.php @@ -1,4 +1,5 @@ get(IndexerFactory::class) ->getIndexer('tt_content') - ->delete() - ; + ->delete(); $this->assertFalse( $this->client->getIndex('typo3content')->exists(), diff --git a/Tests/Functional/Connection/Elasticsearch/IndexTcaTableTest.php b/Tests/Functional/Connection/Elasticsearch/IndexTcaTableTest.php index e3614fd4..0c629c33 100644 --- a/Tests/Functional/Connection/Elasticsearch/IndexTcaTableTest.php +++ b/Tests/Functional/Connection/Elasticsearch/IndexTcaTableTest.php @@ -1,4 +1,5 @@ get(IndexerFactory::class) ->getIndexer('tt_content') - ->indexAllDocuments() - ; + ->indexAllDocuments(); $response = $this->client->request('typo3content/_search?q=*:*'); @@ -53,7 +56,7 @@ public function indexBasicTtContent() $this->assertSame($response->getData()['hits']['total'], 3, 'Not exactly 3 documents were indexed.'); $this->assertSame( 'indexed content element', - $response->getData()['hits']['hits'][2]['_source']['header'], + $response->getData()['hits']['hits'][0]['_source']['header'], 'Record was not indexed.' ); } @@ -66,8 +69,7 @@ public function indexSingleBasicTtContent() \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(ObjectManager::class) ->get(IndexerFactory::class) ->getIndexer('tt_content') - ->indexDocument(6) - ; + ->indexDocument(6); $response = $this->client->request('typo3content/_search?q=*:*'); @@ -89,8 +91,7 @@ public function indexingNonConfiguredTableWillThrowException() { \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(ObjectManager::class) ->get(IndexerFactory::class) - ->getIndexer('non_existing_table') - ; + ->getIndexer('non_existing_table'); } /** @@ -101,8 +102,7 @@ public function canHandleExistingIndex() { $indexer = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(ObjectManager::class) ->get(IndexerFactory::class) - ->getIndexer('tt_content') - ; + ->getIndexer('tt_content'); $indexer->indexAllDocuments(); @@ -129,8 +129,7 @@ public function indexingRespectsUserWhereClause() \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(ObjectManager::class) ->get(IndexerFactory::class) ->getIndexer('tt_content') - ->indexAllDocuments() - ; + ->indexAllDocuments(); $response = $this->client->request('typo3content/_search?q=*:*'); @@ -162,8 +161,7 @@ public function resolvesRelations() \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(ObjectManager::class) ->get(IndexerFactory::class) ->getIndexer('tt_content') - ->indexAllDocuments() - ; + ->indexAllDocuments(); $response = $this->client->request('typo3content/_search?q=*:*'); $this->assertTrue($response->isOk(), 'Elastica did not answer with ok code.'); @@ -171,11 +169,13 @@ public function resolvesRelations() $response = $this->client->request('typo3content/_search?q=uid:11'); $this->assertArraySubset( - ['_source' => [ - 'uid' => '11', - 'CType' => 'Header', // Testing items - 'categories' => ['Category 2', 'Category 1'], // Testing mm - ]], + [ + '_source' => [ + 'uid' => '11', + 'CType' => 'Header', // Testing items + 'categories' => ['Category 2', 'Category 1'], // Testing mm + ] + ], $response->getData()['hits']['hits'][0], false, 'Record was not indexed with resolved category relations to multiple values.' @@ -183,11 +183,13 @@ public function resolvesRelations() $response = $this->client->request('typo3content/_search?q=uid:12'); $this->assertArraySubset( - ['_source' => [ - 'uid' => '12', - 'CType' => 'Header', - 'categories' => ['Category 2'], - ]], + [ + '_source' => [ + 'uid' => '12', + 'CType' => 'Header', + 'categories' => ['Category 2'], + ] + ], $response->getData()['hits']['hits'][0], false, 'Record was not indexed with resolved category relations to a single value.' @@ -195,10 +197,12 @@ public function resolvesRelations() $response = $this->client->request('typo3content/_search?q=uid:6'); $this->assertArraySubset( - ['_source' => [ - 'uid' => '6', - 'categories' => null, - ]], + [ + '_source' => [ + 'uid' => '6', + 'categories' => null, + ] + ], $response->getData()['hits']['hits'][0], false, 'Record was indexed with resolved category relation, but should not have any.' @@ -213,8 +217,7 @@ public function indexingDeletedRecordIfRecordShouldBeIndexedButIsNoLongerAvailab \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(ObjectManager::class) ->get(IndexerFactory::class) ->getIndexer('tt_content') - ->indexAllDocuments() - ; + ->indexAllDocuments(); $response = $this->client->request('typo3content/_search?q=*:*'); $this->assertSame($response->getData()['hits']['total'], 3, 'Not exactly 3 documents were indexed.'); @@ -234,8 +237,7 @@ public function indexingDeletedRecordIfRecordShouldBeIndexedButIsNoLongerAvailab \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(ObjectManager::class) ->get(IndexerFactory::class) ->getIndexer('tt_content') - ->indexDocument(10) - ; + ->indexDocument(10); $response = $this->client->request('typo3content/_search?q=*:*'); $this->assertSame($response->getData()['hits']['total'], 2, 'Not exactly 2 document is in index.'); diff --git a/Tests/Functional/DataProcessing/ContentObjectDataProcessorAdapterProcessorTest.php b/Tests/Functional/DataProcessing/ContentObjectDataProcessorAdapterProcessorTest.php index bb997cf5..f801bd04 100644 --- a/Tests/Functional/DataProcessing/ContentObjectDataProcessorAdapterProcessorTest.php +++ b/Tests/Functional/DataProcessing/ContentObjectDataProcessorAdapterProcessorTest.php @@ -1,4 +1,5 @@ + backupGlobals="true" + backupStaticAttributes="false" + bootstrap="Bootstrap.php" + colors="true" + convertErrorsToExceptions="false" + convertWarningsToExceptions="false" + forceCoversAnnotation="false" + processIsolation="true" + stopOnError="false" + stopOnFailure="false" + stopOnIncomplete="false" + stopOnSkipped="false" + verbose="false"> diff --git a/Tests/Functional/Hooks/DataHandler/AbstractDataHandlerTest.php b/Tests/Functional/Hooks/DataHandler/AbstractDataHandlerTest.php index 84ac0bda..0717cc76 100644 --- a/Tests/Functional/Hooks/DataHandler/AbstractDataHandlerTest.php +++ b/Tests/Functional/Hooks/DataHandler/AbstractDataHandlerTest.php @@ -1,4 +1,5 @@ isLegacyVersion()) { return isset($record['uid']) && $record['uid'] === '1' && isset($record['pid']) && $record['pid'] === '1' - && isset($record['colPos']) && $record['colPos'] === '1' - ; + && isset($record['colPos']) && $record['colPos'] === '1'; } return isset($record['uid']) && $record['uid'] === 1 && isset($record['pid']) && $record['pid'] === 1 - && isset($record['colPos']) && $record['colPos'] === 1 - ; + && isset($record['colPos']) && $record['colPos'] === 1; }) ], [ @@ -132,14 +128,12 @@ public function updateWillBeTriggeredForNewTtContent() if ($this->isLegacyVersion()) { return isset($record['uid']) && $record['uid'] === '2' && isset($record['pid']) && $record['pid'] === '1' - && isset($record['header']) && $record['header'] === 'a new record' - ; + && isset($record['header']) && $record['header'] === 'a new record'; } return isset($record['uid']) && $record['uid'] === 2 && isset($record['pid']) && $record['pid'] === 1 - && isset($record['header']) && $record['header'] === 'a new record' - ; + && isset($record['header']) && $record['header'] === 'a new record'; }) ], [ diff --git a/Tests/Functional/Hooks/DataHandler/ProcessesAllowedTablesWithMultipleTablesConfiguredTest.php b/Tests/Functional/Hooks/DataHandler/ProcessesAllowedTablesWithMultipleTablesConfiguredTest.php index a30beb4b..e16ade4e 100644 --- a/Tests/Functional/Hooks/DataHandler/ProcessesAllowedTablesWithMultipleTablesConfiguredTest.php +++ b/Tests/Functional/Hooks/DataHandler/ProcessesAllowedTablesWithMultipleTablesConfiguredTest.php @@ -1,4 +1,5 @@ [ diff --git a/Tests/Unit/Command/IndexCommandControllerTest.php b/Tests/Unit/Command/IndexCommandControllerTest.php index 9dcc7f33..bfc94a8f 100644 --- a/Tests/Unit/Command/IndexCommandControllerTest.php +++ b/Tests/Unit/Command/IndexCommandControllerTest.php @@ -1,4 +1,5 @@ [ @@ -109,7 +110,7 @@ public function conditionsAreHandledAsExpected(array $entries, array $expected) ); } - public function possibleConditionEntries() : array + public function possibleConditionEntries(): array { return [ 'Nothing in array' => [ diff --git a/Tests/Unit/Connection/Elasticsearch/FacetOptionTest.php b/Tests/Unit/Connection/Elasticsearch/FacetOptionTest.php index 696762c7..9b4d822c 100644 --- a/Tests/Unit/Connection/Elasticsearch/FacetOptionTest.php +++ b/Tests/Unit/Connection/Elasticsearch/FacetOptionTest.php @@ -1,4 +1,5 @@ subject->expects($this->once()) ->method('getRecord') ->with(1) - ->willReturn($record) - ; + ->willReturn($record); $this->connection->expects($this->once())->method('addDocument')->with('testTable', $expectedRecord); $this->subject->indexDocument(1); @@ -147,8 +147,7 @@ public function executesNoDataProcessingForMissingConfiguration() $this->subject->expects($this->once()) ->method('getRecord') ->with(1) - ->willReturn($record) - ; + ->willReturn($record); $this->connection->expects($this->once())->method('addDocument')->with('testTable', $expectedRecord); $this->subject->indexDocument(1); diff --git a/Tests/Unit/Domain/Index/TcaIndexer/TcaTableServiceTest.php b/Tests/Unit/Domain/Index/TcaIndexer/TcaTableServiceTest.php index f4706138..59cf8a70 100644 --- a/Tests/Unit/Domain/Index/TcaIndexer/TcaTableServiceTest.php +++ b/Tests/Unit/Domain/Index/TcaIndexer/TcaTableServiceTest.php @@ -1,4 +1,5 @@ [ 'type' => 'most_fields', 'query' => 'SearchWord', - 'fields' => [ - '_all', - ], ], ], ], @@ -272,9 +270,6 @@ public function minimumShouldMatchIsAddedToQuery() 'multi_match' => [ 'type' => 'most_fields', 'query' => 'SearchWord', - 'fields' => [ - '_all', - ], 'minimum_should_match' => '50%', ], ], @@ -378,9 +373,6 @@ public function factorBoostIsAddedToQuery() 'multi_match' => [ 'type' => 'most_fields', 'query' => 'SearchWord', - 'fields' => [ - '_all', - ], ], ], ], @@ -670,7 +662,7 @@ protected function configureConfigurationMockWithDefault() ->method('get') ->will($this->returnCallback(function ($configName) { if ($configName === 'searching.fields.query') { - return '_all'; + return ''; } throw new InvalidArgumentException(); diff --git a/Tests/Unit/Domain/Search/SearchServiceTest.php b/Tests/Unit/Domain/Search/SearchServiceTest.php index 20ff1b4c..3a6bff81 100644 --- a/Tests/Unit/Domain/Search/SearchServiceTest.php +++ b/Tests/Unit/Domain/Search/SearchServiceTest.php @@ -1,4 +1,5 @@ method('search') ->with($this->callback(function ($searchRequest) { return $searchRequest->getFilter() === [ - 'anotherProperty' => 'anything', - 'property' => 'something', - ]; + 'anotherProperty' => 'anything', + 'property' => 'something', + ]; })) ->willReturn($this->getMockBuilder(SearchResultInterface::class)->getMock()); diff --git a/Tests/Unit/Hook/DataHandlerTest.php b/Tests/Unit/Hook/DataHandlerTest.php index 4cfb8d2b..5cb0bdcc 100644 --- a/Tests/Unit/Hook/DataHandlerTest.php +++ b/Tests/Unit/Hook/DataHandlerTest.php @@ -1,4 +1,5 @@ clearCachePostProc($parameters, $coreDataHandlerMock); } - public function getPossibleCallCombinations() : array + public function getPossibleCallCombinations(): array { return [ 'Editor triggered cache clear of page manual' => [ @@ -77,7 +78,7 @@ public function getPossibleCallCombinations() : array ], 'Editor changed records on a page' => [ 'parameters' => [ - 'uid_page' =>10, + 'uid_page' => 10, ], 'expectCall' => true, ], @@ -112,6 +113,7 @@ public function indexingIsNotCalledForCacheClearIfDataIsInvalid() 'cacheCmd' => 'NEW343', ], $coreDataHandlerMock); } + /** * @test */ diff --git a/Tests/Unit/Integration/Form/Finisher/DataHandlerFinisherTest.php b/Tests/Unit/Integration/Form/Finisher/DataHandlerFinisherTest.php index a5a7d0e3..a82c52fe 100644 --- a/Tests/Unit/Integration/Form/Finisher/DataHandlerFinisherTest.php +++ b/Tests/Unit/Integration/Form/Finisher/DataHandlerFinisherTest.php @@ -1,4 +1,5 @@ subject->execute($this->finisherContextMock); } - public function possibleFinisherSetup() : array + public function possibleFinisherSetup(): array { return [ 'valid update configuration' => [ @@ -118,7 +119,7 @@ public function nothingHappensIfUnknownActionIsConfigured(array $options) $this->subject->execute($this->finisherContextMock); } - public function invalidFinisherSetup() : array + public function invalidFinisherSetup(): array { return [ 'missing options' => [ diff --git a/Tests/Unit/UnitTests.xml b/Tests/Unit/UnitTests.xml index d8285be8..5237e4e1 100644 --- a/Tests/Unit/UnitTests.xml +++ b/Tests/Unit/UnitTests.xml @@ -1,18 +1,18 @@ + colors="true" + convertErrorsToExceptions="false" + convertWarningsToExceptions="false" + forceCoversAnnotation="false" + processIsolation="false" + stopOnError="false" + stopOnFailure="false" + stopOnIncomplete="false" + stopOnSkipped="false" + verbose="false"> From 23f3d0df92c3d7f7f9e321a825a69dd7eec943d2 Mon Sep 17 00:00:00 2001 From: Benjamin Serfhos Date: Fri, 26 Oct 2018 09:46:01 +0200 Subject: [PATCH 17/73] [TASK] Add functional test for deleteDocuments functionality --- Classes/Connection/Elasticsearch.php | 7 +- .../Elasticsearch/IndexDeletionTest.php | 52 +++++++ .../Fixtures/Indexing/IndexDeletion.xml | 129 ++++++++++++++++++ 3 files changed, 186 insertions(+), 2 deletions(-) create mode 100644 Tests/Functional/Fixtures/Indexing/IndexDeletion.xml diff --git a/Classes/Connection/Elasticsearch.php b/Classes/Connection/Elasticsearch.php index 873b09b6..f5bc5d23 100644 --- a/Classes/Connection/Elasticsearch.php +++ b/Classes/Connection/Elasticsearch.php @@ -209,8 +209,11 @@ public function deleteIndexByQuery(Query $query) ); return; } - - $index->deleteByQuery($query); + $response = $index->deleteByQuery($query); + if ($response->getData()['deleted'] > 0) { + // Refresh index when delete query is invoked + $index->refresh(); + } } /** diff --git a/Tests/Functional/Connection/Elasticsearch/IndexDeletionTest.php b/Tests/Functional/Connection/Elasticsearch/IndexDeletionTest.php index 9e6fb029..ee14f259 100644 --- a/Tests/Functional/Connection/Elasticsearch/IndexDeletionTest.php +++ b/Tests/Functional/Connection/Elasticsearch/IndexDeletionTest.php @@ -26,6 +26,17 @@ class IndexDeletionTest extends AbstractFunctionalTestCase { + /** + * @return array + */ + protected function getDataSets() + { + return array_merge( + parent::getDataSets(), + ['EXT:search_core/Tests/Functional/Fixtures/Indexing/IndexDeletion.xml'] + ); + } + /** * @test */ @@ -47,4 +58,45 @@ public function indexIsDeleted() 'Index could not be deleted through command controller.' ); } + + /** + * @test + */ + public function documentsAreDeleted() + { + $index = $this->client->getIndex('typo3content'); + $index->create(); + $this->assertTrue( + $index->exists(), + 'Could not create index for test.' + ); + + $contentIndexer = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(ObjectManager::class) + ->get(IndexerFactory::class) + ->getIndexer('tt_content'); + $pageIndexer = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(ObjectManager::class) + ->get(IndexerFactory::class) + ->getIndexer('pages'); + + $response = $this->client->request('typo3content/_search?q=*:*'); + $this->assertSame($response->getData()['hits']['total'], 0, 'Index should be empty.'); + + $contentIndexer->indexAllDocuments(); + $response = $this->client->request('typo3content/_search?q=*:*'); + $this->assertSame($response->getData()['hits']['total'], 3, 'Not exactly 3 documents are in index.'); + + $pageIndexer->indexAllDocuments(); + $response = $this->client->request('typo3content/_search?q=*:*'); + $this->assertSame($response->getData()['hits']['total'], 5, 'Not exactly 5 documents are in index.'); + + $contentIndexer->deleteDocuments(); + $response = $this->client->request('typo3content/_search?q=*:*'); + $this->assertSame($response->getData()['hits']['total'], 2, 'Not exactly 2 documents are in index.'); + + $pageIndexer->deleteDocuments(); + $response = $this->client->request('typo3content/_search?q=*:*'); + $this->assertSame($response->getData()['hits']['total'], 0, 'Index should be empty.'); + + $index->delete(); + } } diff --git a/Tests/Functional/Fixtures/Indexing/IndexDeletion.xml b/Tests/Functional/Fixtures/Indexing/IndexDeletion.xml new file mode 100644 index 00000000..409e46cd --- /dev/null +++ b/Tests/Functional/Fixtures/Indexing/IndexDeletion.xml @@ -0,0 +1,129 @@ + + + + 6 + 1 + 1480686370 + 1480686370 + 0 + 72 + header +
indexed content element
+ this is the content of header content element that should get indexed + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +
+ + + 7 + 1 + 1480686371 + 1480686370 + 0 + 72 + header +
endtime hidden record
+ + 0 + 0 + 0 + 0 + 0 + 1481305963 + 0 + 0 +
+ + + 8 + 1 + 1480686370 + 1480686370 + 1 + 72 + header +
Hidden record
+ + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +
+ + + 9 + 1 + 1480686370 + 1480686370 + 0 + 72 + div +
not indexed due to ctype
+ this is the content of div content element that should not get indexed + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +
+ + + 10 + 1 + 1480686370 + 1480686370 + 0 + 72 + html +
Indexed without html tags
+ <p>Some text in paragraph</p> + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +
+ + + 100 + 2 + 1480686370 + 1480686370 + 0 + 72 + header +
Indexed on page 2
+ This element is on a different page + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +
+ + + 2 + 1 + Second page with content + Used to check whether content is indexed only for parent page. + +
From b8de35adee98939e01ddc0de543627e6f8de3db2 Mon Sep 17 00:00:00 2001 From: Benjamin Serfhos Date: Fri, 26 Oct 2018 10:49:43 +0200 Subject: [PATCH 18/73] [BUGFIX] Remove _all from unit tests --- Classes/Domain/Search/QueryFactory.php | 4 +++- Tests/Unit/Command/IndexCommandControllerTest.php | 2 +- Tests/Unit/Domain/Search/QueryFactoryTest.php | 6 +++--- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Classes/Domain/Search/QueryFactory.php b/Classes/Domain/Search/QueryFactory.php index c2975608..6d9fcae2 100644 --- a/Classes/Domain/Search/QueryFactory.php +++ b/Classes/Domain/Search/QueryFactory.php @@ -126,7 +126,9 @@ protected function addSearch(SearchRequestInterface $searchRequest, array &$quer try { $fieldsToQuery = GeneralUtility::trimExplode(',', $this->configuration->get('searching.fields.query'), true); - $matchExpression['fields'] = $fieldsToQuery; + if ($fieldsToQuery !== []) { + $matchExpression['fields'] = $fieldsToQuery; + } } catch (InvalidArgumentException $e) { // Nothing configured } diff --git a/Tests/Unit/Command/IndexCommandControllerTest.php b/Tests/Unit/Command/IndexCommandControllerTest.php index bfc94a8f..feb34502 100644 --- a/Tests/Unit/Command/IndexCommandControllerTest.php +++ b/Tests/Unit/Command/IndexCommandControllerTest.php @@ -108,7 +108,7 @@ public function deletionIsPossible() ->will($this->returnValue($indexerMock)); $indexerMock->expects($this->once()) - ->method('delete'); + ->method('deleteDocuments'); $this->subject->deleteCommand('allowedTable'); } diff --git a/Tests/Unit/Domain/Search/QueryFactoryTest.php b/Tests/Unit/Domain/Search/QueryFactoryTest.php index 704abae9..570d5f00 100644 --- a/Tests/Unit/Domain/Search/QueryFactoryTest.php +++ b/Tests/Unit/Domain/Search/QueryFactoryTest.php @@ -298,7 +298,7 @@ public function boostsAreAddedToQuery() ['searching.fieldValueFactor'] ) ->will($this->onConsecutiveCalls( - '_all', + '', [ 'search_title' => 3, 'search_abstract' => 1.5, @@ -355,7 +355,7 @@ public function factorBoostIsAddedToQuery() ['searching.fieldValueFactor'] ) ->will($this->onConsecutiveCalls( - '_all', + '', $this->throwException(new InvalidArgumentException), $this->throwException(new InvalidArgumentException), $this->throwException(new InvalidArgumentException), @@ -526,7 +526,7 @@ public function scriptFieldsAreAddedToQuery() ['searching.fieldValueFactor'] ) ->will($this->onConsecutiveCalls( - '_all', + '', $this->throwException(new InvalidArgumentException), $this->throwException(new InvalidArgumentException), [ From 6e492d2bdb4353c169b861244d966488e8589313 Mon Sep 17 00:00:00 2001 From: Benjamin Serfhos Date: Fri, 26 Oct 2018 10:56:57 +0200 Subject: [PATCH 19/73] [FEATURE] Added flush command as indexation is now into one --- Classes/Command/IndexCommandController.php | 16 ++++++++++++++ .../Command/IndexCommandControllerTest.php | 21 +++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/Classes/Command/IndexCommandController.php b/Classes/Command/IndexCommandController.php index f558f40d..e0929c52 100644 --- a/Classes/Command/IndexCommandController.php +++ b/Classes/Command/IndexCommandController.php @@ -84,4 +84,20 @@ public function deleteCommand(string $identifier) } } } + + /** + * Will delete the full index. + * + * @param string $identifier + * @return void + */ + public function flushCommand(string $identifier = 'pages') + { + try { + $this->indexerFactory->getIndexer($identifier)->delete(); + $this->outputLine('Default configured indices were deleted via ' . $identifier . '.'); + } catch (NoMatchingIndexerException $e) { + $this->outputLine('No indexer found for: ' . $identifier); + } + } } diff --git a/Tests/Unit/Command/IndexCommandControllerTest.php b/Tests/Unit/Command/IndexCommandControllerTest.php index feb34502..48ddd34b 100644 --- a/Tests/Unit/Command/IndexCommandControllerTest.php +++ b/Tests/Unit/Command/IndexCommandControllerTest.php @@ -112,6 +112,27 @@ public function deletionIsPossible() $this->subject->deleteCommand('allowedTable'); } + /** + * @test + */ + public function flushIsPossible() + { + $indexerMock = $this->getMockBuilder(TcaIndexer::class) + ->disableOriginalConstructor() + ->getMock(); + $this->subject->expects($this->once()) + ->method('outputLine') + ->with('Default configured indices were deleted via pages.'); + $this->indexerFactory->expects($this->once()) + ->method('getIndexer') + ->with('pages') + ->will($this->returnValue($indexerMock)); + + $indexerMock->expects($this->once()) + ->method('delete'); + $this->subject->flushCommand('pages'); + } + /** * @test */ From a3ccc123c4e97d7a5b9e70aeab278ce72999d749 Mon Sep 17 00:00:00 2001 From: Benjamin Serfhos Date: Fri, 26 Oct 2018 11:29:37 +0200 Subject: [PATCH 20/73] [TASK] Make sure CGL is correct --- .../Connection/Elasticsearch/SearchResult.php | 6 +++++- .../Domain/Index/TcaIndexer/TcaTableService.php | 5 ++++- Classes/Domain/Search/QueryFactory.php | 6 +++++- .../TcaRelationResolvingProcessorTest.php | 16 ++++++++++++---- Tests/Functional/Indexing/PagesIndexerTest.php | 15 ++++++++++++--- Tests/Functional/Indexing/TcaIndexerTest.php | 7 ++++++- 6 files changed, 44 insertions(+), 11 deletions(-) diff --git a/Classes/Connection/Elasticsearch/SearchResult.php b/Classes/Connection/Elasticsearch/SearchResult.php index a41bded6..5773a50c 100644 --- a/Classes/Connection/Elasticsearch/SearchResult.php +++ b/Classes/Connection/Elasticsearch/SearchResult.php @@ -132,7 +132,11 @@ protected function initFacets() $this->facets = []; if ($this->result->hasAggregations()) { foreach ($this->result->getAggregations() as $aggregationName => $aggregation) { - $this->facets[$aggregationName] = $this->objectManager->get(Facet::class, $aggregationName, $aggregation); + $this->facets[$aggregationName] = $this->objectManager->get( + Facet::class, + $aggregationName, + $aggregation + ); } } } diff --git a/Classes/Domain/Index/TcaIndexer/TcaTableService.php b/Classes/Domain/Index/TcaIndexer/TcaTableService.php index c390d370..5f69da5b 100644 --- a/Classes/Domain/Index/TcaIndexer/TcaTableService.php +++ b/Classes/Domain/Index/TcaIndexer/TcaTableService.php @@ -172,7 +172,10 @@ public function prepareRecord(array &$record) $record['search_title'] = $record[$this->tca['ctrl']['label']]; } - if (isset($this->tca['ctrl']['enablecolumns']['fe_group'], $record[$this->tca['ctrl']['enablecolumns']['fe_group']])) { + if (isset( + $this->tca['ctrl']['enablecolumns']['fe_group'], + $record[$this->tca['ctrl']['enablecolumns']['fe_group']] + )) { $groups = GeneralUtility::intExplode( ',', $record[$this->tca['ctrl']['enablecolumns']['fe_group']], diff --git a/Classes/Domain/Search/QueryFactory.php b/Classes/Domain/Search/QueryFactory.php index 6d9fcae2..f397a21a 100644 --- a/Classes/Domain/Search/QueryFactory.php +++ b/Classes/Domain/Search/QueryFactory.php @@ -125,7 +125,11 @@ protected function addSearch(SearchRequestInterface $searchRequest, array &$quer ]; try { - $fieldsToQuery = GeneralUtility::trimExplode(',', $this->configuration->get('searching.fields.query'), true); + $fieldsToQuery = GeneralUtility::trimExplode( + ',', + $this->configuration->get('searching.fields.query'), + true + ); if ($fieldsToQuery !== []) { $matchExpression['fields'] = $fieldsToQuery; } diff --git a/Tests/Functional/DataProcessing/TcaRelationResolvingProcessorTest.php b/Tests/Functional/DataProcessing/TcaRelationResolvingProcessorTest.php index 62acbc4c..b2e5b775 100644 --- a/Tests/Functional/DataProcessing/TcaRelationResolvingProcessorTest.php +++ b/Tests/Functional/DataProcessing/TcaRelationResolvingProcessorTest.php @@ -34,7 +34,9 @@ class TcaRelationResolvingProcessorTest extends AbstractFunctionalTestCase */ public function resolveInlineRelation() { - $this->importDataSet('EXT:search_core/Tests/Functional/Fixtures/Indexing/TcaIndexer/RelationResolver/InlineRelation.xml'); + $this->importDataSet( + 'EXT:search_core/Tests/Functional/Fixtures/Indexing/TcaIndexer/RelationResolver/InlineRelation.xml' + ); $objectManager = GeneralUtility::makeInstance(ObjectManager::class); $table = 'sys_file'; @@ -56,7 +58,9 @@ public function resolveInlineRelation() */ public function resolveStaticSelectItems() { - $this->importDataSet('EXT:search_core/Tests/Functional/Fixtures/Indexing/TcaIndexer/RelationResolver/StaticSelectItems.xml'); + $this->importDataSet( + 'EXT:search_core/Tests/Functional/Fixtures/Indexing/TcaIndexer/RelationResolver/StaticSelectItems.xml' + ); $objectManager = GeneralUtility::makeInstance(ObjectManager::class); $table = 'tt_content'; @@ -75,7 +79,9 @@ public function resolveStaticSelectItems() */ public function resolveForeignDb() { - $this->importDataSet('EXT:search_core/Tests/Functional/Fixtures/Indexing/TcaIndexer/RelationResolver/ForeignDb.xml'); + $this->importDataSet( + 'EXT:search_core/Tests/Functional/Fixtures/Indexing/TcaIndexer/RelationResolver/ForeignDb.xml' + ); $objectManager = GeneralUtility::makeInstance(ObjectManager::class); $table = 'tt_content'; @@ -97,7 +103,9 @@ public function resolveForeignDb() */ public function resolveForeignMmSelect() { - $this->importDataSet('EXT:search_core/Tests/Functional/Fixtures/Indexing/TcaIndexer/RelationResolver/ForeignMmSelect.xml'); + $this->importDataSet( + 'EXT:search_core/Tests/Functional/Fixtures/Indexing/TcaIndexer/RelationResolver/ForeignMmSelect.xml' + ); $objectManager = GeneralUtility::makeInstance(ObjectManager::class); $table = 'tt_content'; diff --git a/Tests/Functional/Indexing/PagesIndexerTest.php b/Tests/Functional/Indexing/PagesIndexerTest.php index 5c7f366c..3a080ea6 100644 --- a/Tests/Functional/Indexing/PagesIndexerTest.php +++ b/Tests/Functional/Indexing/PagesIndexerTest.php @@ -96,12 +96,21 @@ public function rootLineIsRespectedDuringIndexing($dataSetPath) $indexer->indexAllDocuments(); } + /** + * @return array + */ public function rootLineDataSets() { return [ - 'Broken root line' => ['EXT:search_core/Tests/Functional/Fixtures/Indexing/PagesIndexer/BrokenRootLine.xml'], - 'Recycler doktype' => ['EXT:search_core/Tests/Functional/Fixtures/Indexing/PagesIndexer/Recycler.xml'], - 'Extended timing to sub pages' => ['EXT:search_core/Tests/Functional/Fixtures/Indexing/PagesIndexer/InheritedTiming.xml'], + 'Broken root line' => [ + 'EXT:search_core/Tests/Functional/Fixtures/Indexing/PagesIndexer/BrokenRootLine.xml' + ], + 'Recycler doktype' => [ + 'EXT:search_core/Tests/Functional/Fixtures/Indexing/PagesIndexer/Recycler.xml' + ], + 'Extended timing to sub pages' => [ + 'EXT:search_core/Tests/Functional/Fixtures/Indexing/PagesIndexer/InheritedTiming.xml' + ], ]; } } diff --git a/Tests/Functional/Indexing/TcaIndexerTest.php b/Tests/Functional/Indexing/TcaIndexerTest.php index f413bfd0..5a2328b1 100644 --- a/Tests/Functional/Indexing/TcaIndexerTest.php +++ b/Tests/Functional/Indexing/TcaIndexerTest.php @@ -31,6 +31,9 @@ class TcaIndexerTest extends AbstractFunctionalTestCase { + /** + * @return array + */ protected function getTypoScriptFilesForFrontendRootPage() { return array_merge( @@ -44,7 +47,9 @@ protected function getTypoScriptFilesForFrontendRootPage() */ public function respectRootLineBlacklist() { - $this->importDataSet('EXT:search_core/Tests/Functional/Fixtures/Indexing/TcaIndexer/RespectRootLineBlacklist.xml'); + $this->importDataSet( + 'EXT:search_core/Tests/Functional/Fixtures/Indexing/TcaIndexer/RespectRootLineBlacklist.xml' + ); $objectManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(ObjectManager::class); $tableName = 'tt_content'; $tableService = $objectManager->get( From 7b5a0039ed8abc953fe2826db7a0a6a0e671c7a6 Mon Sep 17 00:00:00 2001 From: Benjamin Serfhos Date: Fri, 26 Oct 2018 13:42:46 +0200 Subject: [PATCH 21/73] [TASK] Try composer update for travis build --- Tests/InstallPatches/composer.json.patch | 4 ++-- composer.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Tests/InstallPatches/composer.json.patch b/Tests/InstallPatches/composer.json.patch index 6f11cdc7..49e36b0e 100644 --- a/Tests/InstallPatches/composer.json.patch +++ b/Tests/InstallPatches/composer.json.patch @@ -3,11 +3,11 @@ index 83e5f47..e9fa296 100644 --- a/composer.json +++ b/composer.json @@ -21,8 +21,7 @@ - "ruflin/elastica": "~3.2" + "ruflin/elastica": "^6.0.2" }, "require-dev": { - "phpunit/phpunit": "~6.4.4", -- "typo3/testing-framework": "~1.1.5", +- "typo3/testing-framework": "^2.0.0", + "phpunit/phpunit": "~5.7.0", "squizlabs/php_codesniffer": "~3.1.1" }, diff --git a/composer.json b/composer.json index dc13e7f7..89acd0aa 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,7 @@ }, "require-dev": { "phpunit/phpunit": "~6.4.4", - "typo3/testing-framework": "~1.1.5", + "typo3/testing-framework": "^2.0.0", "squizlabs/php_codesniffer": "~3.1.1" }, "config": { From 35fdc6905fe94dad87a35f905d4ad928102085ad Mon Sep 17 00:00:00 2001 From: Benjamin Serfhos Date: Fri, 26 Oct 2018 14:11:12 +0200 Subject: [PATCH 22/73] [TASK] Enable elasticsearch version 6 for travis --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 54c26374..c5d90737 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,7 @@ addons: 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 restart + - curl -O https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-6.4.1.deb && sudo dpkg -i --force-confnew elasticsearch-6.4.1.deb && sudo service elasticsearch restart - mysql -u root -e 'GRANT ALL ON `typo3_ci_ft%`.* TO travis@127.0.0.1;' language: php From 0d14f80f62c43eb6842d98cacd46195d9ebc402e Mon Sep 17 00:00:00 2001 From: Benjamin Serfhos Date: Fri, 26 Oct 2018 14:48:13 +0200 Subject: [PATCH 23/73] [TASK] Remove support for TYPO3 7.6 --- .travis.yml | 1 - Classes/Compatibility/TypoScriptService76.php | 31 ------------------- .../source/development/contribution.rst | 4 +-- Makefile | 7 ----- Tests/Functional/Bootstrap.php | 4 --- ...bjectDataProcessorAdapterProcessorTest.php | 7 +---- Tests/Unit/Bootstrap.php | 4 --- .../Index/TcaIndexer/TcaTableServiceTest.php | 4 --- composer.json | 2 +- ext_emconf.php | 2 +- 10 files changed, 5 insertions(+), 61 deletions(-) delete mode 100644 Classes/Compatibility/TypoScriptService76.php diff --git a/.travis.yml b/.travis.yml index c5d90737..d4f07e29 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,7 +26,6 @@ env: - typo3DatabaseUsername="travis" - typo3DatabasePassword="" matrix: - - TYPO3_VERSION="~7.6" - TYPO3_VERSION="~8.7" matrix: diff --git a/Classes/Compatibility/TypoScriptService76.php b/Classes/Compatibility/TypoScriptService76.php deleted file mode 100644 index f3b1c89b..00000000 --- a/Classes/Compatibility/TypoScriptService76.php +++ /dev/null @@ -1,31 +0,0 @@ - - * - * 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\Extbase\Service\TypoScriptService as CoreTypoScriptService; - -/** - * Used before TYPO3 CMS 8.7. - */ -class TypoScriptService76 extends CoreTypoScriptService implements TypoScriptServiceInterface -{ -} diff --git a/Documentation/source/development/contribution.rst b/Documentation/source/development/contribution.rst index f65bb214..783c5b95 100644 --- a/Documentation/source/development/contribution.rst +++ b/Documentation/source/development/contribution.rst @@ -41,8 +41,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="searchcoretest87" + export TYPO3_VERSION="~8.7" 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/Makefile b/Makefile index 21f6c315..2646a3cc 100644 --- a/Makefile +++ b/Makefile @@ -11,16 +11,9 @@ typo3DatabasePassword ?= "dev" typo3DatabaseHost ?= "127.0.0.1" sourceOrDist=--prefer-dist -ifeq ($(TYPO3_VERSION),~7.6) - sourceOrDist=--prefer-source -endif .PHONY: install install: clean - if [ $(TYPO3_VERSION) = ~7.6 ]; then \ - patch composer.json Tests/InstallPatches/composer.json.patch; \ - fi - COMPOSER_PROCESS_TIMEOUT=1000 composer require -vv --dev $(sourceOrDist) typo3/cms="$(TYPO3_VERSION)" git checkout composer.json diff --git a/Tests/Functional/Bootstrap.php b/Tests/Functional/Bootstrap.php index 66b8ebaf..9dece76b 100644 --- a/Tests/Functional/Bootstrap.php +++ b/Tests/Functional/Bootstrap.php @@ -2,8 +2,4 @@ $filePath = '.Build/vendor/typo3/testing-framework/Resources/Core/Build/FunctionalTestsBootstrap.php'; -if (getenv('TYPO3_VERSION') === '~7.6') { - $filePath = '.Build/vendor/typo3/cms/typo3/sysext/core/Build/FunctionalTestsBootstrap.php'; -} - require_once dirname(dirname(__DIR__)) . '/' . $filePath; diff --git a/Tests/Functional/DataProcessing/ContentObjectDataProcessorAdapterProcessorTest.php b/Tests/Functional/DataProcessing/ContentObjectDataProcessorAdapterProcessorTest.php index f801bd04..2cbbeb37 100644 --- a/Tests/Functional/DataProcessing/ContentObjectDataProcessorAdapterProcessorTest.php +++ b/Tests/Functional/DataProcessing/ContentObjectDataProcessorAdapterProcessorTest.php @@ -22,7 +22,6 @@ */ use Codappix\SearchCore\Compatibility\TypoScriptService; -use Codappix\SearchCore\Compatibility\TypoScriptService76; use Codappix\SearchCore\DataProcessing\ContentObjectDataProcessorAdapterProcessor; use Codappix\SearchCore\Tests\Functional\AbstractFunctionalTestCase; use TYPO3\CMS\Frontend\DataProcessing\SplitProcessor; @@ -46,11 +45,7 @@ public function contentObjectDataProcessorIsExecuted() 'new_content' => ['value1', 'value2'], ]; - if ($this->isLegacyVersion()) { - $typoScriptService = new TypoScriptService76(); - } else { - $typoScriptService = new TypoScriptService(); - } + $typoScriptService = new TypoScriptService(); $subject = new ContentObjectDataProcessorAdapterProcessor($typoScriptService); $processedData = $subject->processData($record, $configuration); diff --git a/Tests/Unit/Bootstrap.php b/Tests/Unit/Bootstrap.php index 3ed0a1cb..3eb7a83e 100644 --- a/Tests/Unit/Bootstrap.php +++ b/Tests/Unit/Bootstrap.php @@ -2,10 +2,6 @@ $filePath = '.Build/vendor/typo3/testing-framework/Resources/Core/Build/UnitTestsBootstrap.php'; -if (getenv('TYPO3_VERSION') === '~7.6') { - $filePath = '.Build/vendor/typo3/cms/typo3/sysext/core/Build/UnitTestsBootstrap.php'; -} - date_default_timezone_set('UTC'); require_once dirname(dirname(__DIR__)) . '/' . $filePath; diff --git a/Tests/Unit/Domain/Index/TcaIndexer/TcaTableServiceTest.php b/Tests/Unit/Domain/Index/TcaIndexer/TcaTableServiceTest.php index 59cf8a70..c01ece14 100644 --- a/Tests/Unit/Domain/Index/TcaIndexer/TcaTableServiceTest.php +++ b/Tests/Unit/Domain/Index/TcaIndexer/TcaTableServiceTest.php @@ -24,7 +24,6 @@ use Codappix\SearchCore\Configuration\ConfigurationContainerInterface; use Codappix\SearchCore\Domain\Index\TcaIndexer\RelationResolver; use Codappix\SearchCore\Domain\Index\TcaIndexer\TcaTableService; -use Codappix\SearchCore\Domain\Index\TcaIndexer\TcaTableService76; use Codappix\SearchCore\Tests\Unit\AbstractUnitTestCase; use TYPO3\CMS\Core\Database\DatabaseConnection; @@ -53,9 +52,6 @@ public function setUp() $this->databaseConnection = $this->getMockBuilder(DatabaseConnection::class)->getMock(); $className = TcaTableService::class; - if ($this->isLegacyVersion()) { - $className = TcaTableService76::class; - } $this->subject = $this->getMockBuilder($className) ->disableOriginalConstructor() ->setMethods(['getConnection', 'getSystemWhereClause']) diff --git a/composer.json b/composer.json index 89acd0aa..07a679f5 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,7 @@ }, "require": { "php": ">=7.0.0", - "typo3/cms": ">= 7.6.0 < 9.0.0", + "typo3/cms": ">= 8.7.0 < 9.0.0", "ruflin/elastica": "^6.0.2" }, "require-dev": { diff --git a/ext_emconf.php b/ext_emconf.php index ef4aa923..db3f0781 100644 --- a/ext_emconf.php +++ b/ext_emconf.php @@ -7,7 +7,7 @@ 'clearCacheOnLoad' => 1, 'constraints' => [ 'depends' => [ - 'typo3' => '7.6.0-8.7.99', + 'typo3' => '8.7.0-8.7.99', 'php' => '7.0.0-7.2.99' ], 'conflicts' => [], From 577a5624b8c3ca2baaffbd60b1e8737eef331549 Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Sat, 27 Oct 2018 10:55:21 +0200 Subject: [PATCH 24/73] TASK: Remove code base for TYPO3 7.x Also add documentation with breaking change. --- .../ImplementationRegistrationService.php | 57 ------------------- Classes/Compatibility/TypoScriptService.php | 31 ---------- .../TypoScriptServiceInterface.php | 31 ---------- ...entObjectDataProcessorAdapterProcessor.php | 8 +-- Documentation/source/changelog.rst | 1 + .../20181027-remove-cms7-support.rst | 6 ++ Tests/Functional/Bootstrap.php | 5 -- ...bjectDataProcessorAdapterProcessorTest.php | 2 +- Tests/Functional/FunctionalTests.xml | 26 ++++----- Tests/InstallPatches/composer.json.patch | 14 ----- Tests/Unit/Bootstrap.php | 7 --- Tests/Unit/UnitTests.xml | 26 ++++----- ext_localconf.php | 2 - 13 files changed, 38 insertions(+), 178 deletions(-) delete mode 100644 Classes/Compatibility/ImplementationRegistrationService.php delete mode 100644 Classes/Compatibility/TypoScriptService.php delete mode 100644 Classes/Compatibility/TypoScriptServiceInterface.php create mode 100644 Documentation/source/changelog/20181027-remove-cms7-support.rst delete mode 100644 Tests/Functional/Bootstrap.php delete mode 100644 Tests/InstallPatches/composer.json.patch delete mode 100644 Tests/Unit/Bootstrap.php diff --git a/Classes/Compatibility/ImplementationRegistrationService.php b/Classes/Compatibility/ImplementationRegistrationService.php deleted file mode 100644 index 46aa3f0f..00000000 --- a/Classes/Compatibility/ImplementationRegistrationService.php +++ /dev/null @@ -1,57 +0,0 @@ - - * - * 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\Utility\GeneralUtility; -use TYPO3\CMS\Core\Utility\VersionNumberUtility; -use TYPO3\CMS\Extbase\Object\Container\Container; - -/** - * Register different concrete implementations, depending on current TYPO3 version. - * This way we can provide working implementations for multiple TYPO3 versions. - */ -class ImplementationRegistrationService -{ - public static function registerImplementations() - { - $container = GeneralUtility::makeInstance(Container::class); - if (VersionNumberUtility::convertVersionNumberToInteger(TYPO3_version) >= 8000000) { - $container->registerImplementation( - \Codappix\SearchCore\Compatibility\TypoScriptServiceInterface::class, - \Codappix\SearchCore\Compatibility\TypoScriptService::class - ); - $container->registerImplementation( - \Codappix\SearchCore\Domain\Index\TcaIndexer\TcaTableServiceInterface::class, - \Codappix\SearchCore\Domain\Index\TcaIndexer\TcaTableService::class - ); - } else { - $container->registerImplementation( - \Codappix\SearchCore\Compatibility\TypoScriptServiceInterface::class, - \Codappix\SearchCore\Compatibility\TypoScriptService76::class - ); - $container->registerImplementation( - \Codappix\SearchCore\Domain\Index\TcaIndexer\TcaTableServiceInterface::class, - \Codappix\SearchCore\Domain\Index\TcaIndexer\TcaTableService76::class - ); - } - } -} diff --git a/Classes/Compatibility/TypoScriptService.php b/Classes/Compatibility/TypoScriptService.php deleted file mode 100644 index 7934e6ca..00000000 --- a/Classes/Compatibility/TypoScriptService.php +++ /dev/null @@ -1,31 +0,0 @@ - - * - * 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\TypoScript\TypoScriptService as CoreTypoScriptService; - -/** - * Used since TYPO3 CMS 8.7. - */ -class TypoScriptService extends CoreTypoScriptService implements TypoScriptServiceInterface -{ -} diff --git a/Classes/Compatibility/TypoScriptServiceInterface.php b/Classes/Compatibility/TypoScriptServiceInterface.php deleted file mode 100644 index d6bf6d12..00000000 --- a/Classes/Compatibility/TypoScriptServiceInterface.php +++ /dev/null @@ -1,31 +0,0 @@ - - * - * 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. - */ - -/** - * Allows to use DI configuration to switch concrete implementation, depending - * on current TYPO3 Version. - */ -interface TypoScriptServiceInterface -{ - public function convertPlainArrayToTypoScriptArray(array $plainArray); -} diff --git a/Classes/DataProcessing/ContentObjectDataProcessorAdapterProcessor.php b/Classes/DataProcessing/ContentObjectDataProcessorAdapterProcessor.php index 2538ebfe..cf440751 100644 --- a/Classes/DataProcessing/ContentObjectDataProcessorAdapterProcessor.php +++ b/Classes/DataProcessing/ContentObjectDataProcessorAdapterProcessor.php @@ -21,7 +21,7 @@ * 02110-1301, USA. */ -use Codappix\SearchCore\Compatibility\TypoScriptServiceInterface; +use TYPO3\CMS\Core\TypoScript\TypoScriptService; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer; @@ -31,15 +31,15 @@ class ContentObjectDataProcessorAdapterProcessor implements ProcessorInterface { /** - * @var TypoScriptServiceInterface + * @var TypoScriptService */ protected $typoScriptService; /** * ContentObjectDataProcessorAdapterProcessor constructor. - * @param TypoScriptServiceInterface $typoScriptService + * @param TypoScriptService $typoScriptService */ - public function __construct(TypoScriptServiceInterface $typoScriptService) + public function __construct(TypoScriptService $typoScriptService) { $this->typoScriptService = $typoScriptService; } diff --git a/Documentation/source/changelog.rst b/Documentation/source/changelog.rst index 2cad89f0..016ef89c 100644 --- a/Documentation/source/changelog.rst +++ b/Documentation/source/changelog.rst @@ -5,6 +5,7 @@ Changelog :maxdepth: 1 :glob: + changelog/20181027-remove-cms7-support changelog/20180518-75-make-index-name-configurable changelog/20180424-149-extract-relation-resolver-to-data-processing changelog/20180410-148-keep-sys_language_uid diff --git a/Documentation/source/changelog/20181027-remove-cms7-support.rst b/Documentation/source/changelog/20181027-remove-cms7-support.rst new file mode 100644 index 00000000..ec493f1d --- /dev/null +++ b/Documentation/source/changelog/20181027-remove-cms7-support.rst @@ -0,0 +1,6 @@ +Breaking Change "Remove CMS7 support" +===================================== + +We no longer support TYPO3 CMS 7.x. + +Stay at an older release, or upgrade your TYPO3 installation. diff --git a/Tests/Functional/Bootstrap.php b/Tests/Functional/Bootstrap.php deleted file mode 100644 index 9dece76b..00000000 --- a/Tests/Functional/Bootstrap.php +++ /dev/null @@ -1,5 +0,0 @@ - + backupGlobals="true" + backupStaticAttributes="false" + bootstrap="../../.Build/vendor/typo3/testing-framework/Resources/Core/Build/FunctionalTestsBootstrap.php" + colors="true" + convertErrorsToExceptions="false" + convertWarningsToExceptions="false" + forceCoversAnnotation="false" + processIsolation="true" + stopOnError="false" + stopOnFailure="false" + stopOnIncomplete="false" + stopOnSkipped="false" + verbose="false"> diff --git a/Tests/InstallPatches/composer.json.patch b/Tests/InstallPatches/composer.json.patch deleted file mode 100644 index 49e36b0e..00000000 --- a/Tests/InstallPatches/composer.json.patch +++ /dev/null @@ -1,14 +0,0 @@ -diff --git a/composer.json b/composer.json -index 83e5f47..e9fa296 100644 ---- a/composer.json -+++ b/composer.json -@@ -21,8 +21,7 @@ - "ruflin/elastica": "^6.0.2" - }, - "require-dev": { -- "phpunit/phpunit": "~6.4.4", -- "typo3/testing-framework": "^2.0.0", -+ "phpunit/phpunit": "~5.7.0", - "squizlabs/php_codesniffer": "~3.1.1" - }, - "config": { diff --git a/Tests/Unit/Bootstrap.php b/Tests/Unit/Bootstrap.php deleted file mode 100644 index 3eb7a83e..00000000 --- a/Tests/Unit/Bootstrap.php +++ /dev/null @@ -1,7 +0,0 @@ - + colors="true" + convertErrorsToExceptions="false" + convertWarningsToExceptions="false" + forceCoversAnnotation="false" + processIsolation="false" + stopOnError="false" + stopOnFailure="false" + stopOnIncomplete="false" + stopOnSkipped="false" + verbose="false"> diff --git a/ext_localconf.php b/ext_localconf.php index 2b2e48e2..afc2a451 100644 --- a/ext_localconf.php +++ b/ext_localconf.php @@ -61,8 +61,6 @@ '' ); - \Codappix\SearchCore\Compatibility\ImplementationRegistrationService::registerImplementations(); - if (empty($configuration) || (isset($configuration['disable.']['elasticsearch']) && filter_var($configuration['disable.']['elasticsearch'], FILTER_VALIDATE_BOOLEAN) === false) From e5e8f41ad5f35a35b809de9d6b650a0b354ee74b Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Sat, 27 Oct 2018 11:23:31 +0200 Subject: [PATCH 25/73] TASK: Prevent php warning for stdClass constant --- Tests/Unit/Domain/Search/QueryFactoryTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Unit/Domain/Search/QueryFactoryTest.php b/Tests/Unit/Domain/Search/QueryFactoryTest.php index 570d5f00..45b77a99 100644 --- a/Tests/Unit/Domain/Search/QueryFactoryTest.php +++ b/Tests/Unit/Domain/Search/QueryFactoryTest.php @@ -397,7 +397,7 @@ public function emptySearchStringWillNotAddSearchToQuery() $query = $this->subject->create($searchRequest); $this->assertInstanceOf( - stdClass, + 'stdClass', $query->toArray()['query']['match_all'], 'Empty search request does not create expected query.' ); From 30a34c4f153561090694ea2013f07fb11f7b25a4 Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Sat, 27 Oct 2018 11:23:46 +0200 Subject: [PATCH 26/73] FEATURE: Always accept comma separated list of identifiers on CLI * Streamline all commands to always accept a comma separated list of identifiers. * Adjust phpdoc to reflect this feature and provide help on CLI. * Refactor code to move recurring logic to own method. * Provide tests for new feature. * Add documentation for feature. --- Classes/Command/IndexCommandController.php | 71 +++++++------ Classes/Domain/Index/AbstractIndexer.php | 25 ++--- Classes/Domain/Index/IndexerInterface.php | 19 ++-- Classes/Domain/Index/TcaIndexer.php | 2 +- Documentation/source/changelog.rst | 2 + .../20181027-added-flush-command.rst | 6 ++ ...81027-allow-multiple-identifier-on-cli.rst | 4 + .../Command/IndexCommandControllerTest.php | 100 +++++++++++++++++- 8 files changed, 171 insertions(+), 58 deletions(-) create mode 100644 Documentation/source/changelog/20181027-added-flush-command.rst create mode 100644 Documentation/source/changelog/20181027-allow-multiple-identifier-on-cli.rst diff --git a/Classes/Command/IndexCommandController.php b/Classes/Command/IndexCommandController.php index e0929c52..95967137 100644 --- a/Classes/Command/IndexCommandController.php +++ b/Classes/Command/IndexCommandController.php @@ -22,6 +22,7 @@ */ use Codappix\SearchCore\Domain\Index\IndexerFactory; +use Codappix\SearchCore\Domain\Index\IndexerInterface; use Codappix\SearchCore\Domain\Index\NoMatchingIndexerException; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Extbase\Mvc\Controller\CommandController; @@ -46,58 +47,60 @@ public function injectIndexerFactory(IndexerFactory $factory) } /** - * Will index the given identifier. + * Will index all documents for the given identifiers. * - * @param string $identifier + * @param string $identifier Comma separated list of identifiers. * @return void */ - public function indexCommand(string $identifier) + public function indexCommand(string $identifiers) { - // Allow multiple identifiers per import task - $identifiers = GeneralUtility::trimExplode(',', $identifier, true); - foreach ($identifiers as $value) { - try { - $this->indexerFactory->getIndexer($value)->indexAllDocuments(); - $this->outputLine($value . ' was indexed.'); - } catch (NoMatchingIndexerException $e) { - $this->outputLine('No indexer found for: ' . $value); - } - } + $this->executeForIdentifier($identifiers, function (IndexerInterface $indexer) { + $indexer->indexAllDocuments(); + $this->outputLine('Documents in indice ' . $indexer->getIdentifier() . ' were indexed.'); + }); } /** - * Will delete the given identifier. + * Will delete all indexed documents for the given identifiers. * - * @param string $identifier + * @param string $identifier Comma separated list of identifiers. * @return void */ - public function deleteCommand(string $identifier) + public function deleteCommand(string $identifiers) { - // Allow multiple identifiers per import task - $identifiers = GeneralUtility::trimExplode(',', $identifier, true); - foreach ($identifiers as $value) { - try { - $this->indexerFactory->getIndexer($value)->deleteDocuments(); - $this->outputLine($value . ' was deleted.'); - } catch (NoMatchingIndexerException $e) { - $this->outputLine('No indexer found for: ' . $value); - } - } + $this->executeForIdentifier($identifiers, function (IndexerInterface $indexer) { + $indexer->deleteDocuments(); + $this->outputLine('Documents in indice ' . $indexer->getIdentifier() . ' were deleted.'); + }); } /** - * Will delete the full index. + * Will delete the full index for given identifiers. * - * @param string $identifier + * @param string $identifier Comma separated list of identifiers. * @return void */ - public function flushCommand(string $identifier = 'pages') + public function flushCommand(string $identifiers = 'pages') { - try { - $this->indexerFactory->getIndexer($identifier)->delete(); - $this->outputLine('Default configured indices were deleted via ' . $identifier . '.'); - } catch (NoMatchingIndexerException $e) { - $this->outputLine('No indexer found for: ' . $identifier); + $this->executeForIdentifier($identifiers, function (IndexerInterface $indexer) { + $indexer->delete(); + $this->outputLine('Indice ' . $indexer->getIdentifier() . ' was deleted.'); + }); + } + + /** + * Executes the given callback method for each provided identifier. + * + * An indexer is created for each identifier, which is provided as first argument to the callback. + */ + private function executeForIdentifier(string $identifiers, callable $callback) + { + foreach (GeneralUtility::trimExplode(',', $identifiers, true) as $identifier) { + try { + $callback($this->indexerFactory->getIndexer($identifier)); + } catch (NoMatchingIndexerException $e) { + $this->outputLine('No indexer found for: ' . $identifier . '.'); + } } } } diff --git a/Classes/Domain/Index/AbstractIndexer.php b/Classes/Domain/Index/AbstractIndexer.php index e29ff75a..afe61e92 100644 --- a/Classes/Domain/Index/AbstractIndexer.php +++ b/Classes/Domain/Index/AbstractIndexer.php @@ -65,15 +65,6 @@ public function injectLogger(\TYPO3\CMS\Core\Log\LogManager $logManager) $this->logger = $logManager->getLogger(__CLASS__); } - /** - * @param string $identifier - * @return void - */ - public function setIdentifier(string $identifier) - { - $this->identifier = $identifier; - } - /** * AbstractIndexer constructor. * @param ConnectionInterface $connection @@ -120,7 +111,7 @@ public function indexDocument(string $identifier) $this->connection->addDocument($this->getDocumentName(), $record); } catch (NoRecordFoundException $e) { $this->logger->info('Could not index document. Try to delete it therefore.', [$e->getMessage()]); - $this->connection->deleteDocument($this->getDocumentName(), $this->getIdentifier($identifier)); + $this->connection->deleteDocument($this->getDocumentName(), $this->getDocumentIdentifier($identifier)); } $this->logger->info('Finish indexing'); } @@ -194,7 +185,7 @@ protected function generateSearchIdentifiers(array &$record) $record['search_document_type'] = $this->getDocumentName(); } if (!isset($record['search_identifier']) && isset($record['uid'])) { - $record['search_identifier'] = $this->getIdentifier($record['uid']); + $record['search_identifier'] = $this->getDocumentIdentifier($record['uid']); } } @@ -237,6 +228,16 @@ protected function getLimit(): int return 50; } + public function setIdentifier(string $identifier) + { + $this->identifier = $identifier; + } + + public function getIdentifier(): string + { + return $this->identifier; + } + /** * @param integer $offset * @param integer $limit @@ -259,5 +260,5 @@ abstract protected function getDocumentName(): string; * @param string $identifier * @return string */ - abstract public function getIdentifier($identifier): string; + abstract public function getDocumentIdentifier($identifier): string; } diff --git a/Classes/Domain/Index/IndexerInterface.php b/Classes/Domain/Index/IndexerInterface.php index ace52433..3debab15 100644 --- a/Classes/Domain/Index/IndexerInterface.php +++ b/Classes/Domain/Index/IndexerInterface.php @@ -42,24 +42,31 @@ public function indexAllDocuments(); public function indexDocument(string $identifier); /** - * Receives the identifier of the indexer itself. + * Delete the whole index. * - * @param string $identifier * @return void */ - public function setIdentifier(string $identifier); + public function delete(); /** * Delete the whole index. * * @return void */ - public function delete(); + public function deleteDocuments(); /** - * Delete the whole index. + * Receives the identifier of the indexer itself. * + * @param string $identifier * @return void */ - public function deleteDocuments(); + public function setIdentifier(string $identifier); + + /** + * Returnes the identifier of the indexer. + * + * @return string + */ + public function getIdentifier(): string; } diff --git a/Classes/Domain/Index/TcaIndexer.php b/Classes/Domain/Index/TcaIndexer.php index 74141d02..69fdf989 100644 --- a/Classes/Domain/Index/TcaIndexer.php +++ b/Classes/Domain/Index/TcaIndexer.php @@ -100,7 +100,7 @@ protected function getDocumentName(): string * @param string $identifier * @return string */ - public function getIdentifier($identifier): string + public function getDocumentIdentifier($identifier): string { return $this->getDocumentName() . '-' . $identifier; } diff --git a/Documentation/source/changelog.rst b/Documentation/source/changelog.rst index 016ef89c..94ad4d96 100644 --- a/Documentation/source/changelog.rst +++ b/Documentation/source/changelog.rst @@ -5,6 +5,8 @@ Changelog :maxdepth: 1 :glob: + changelog/20181027-added-flush-command + changelog/20181027-allow-multiple-identifiers-on-cli changelog/20181027-remove-cms7-support changelog/20180518-75-make-index-name-configurable changelog/20180424-149-extract-relation-resolver-to-data-processing diff --git a/Documentation/source/changelog/20181027-added-flush-command.rst b/Documentation/source/changelog/20181027-added-flush-command.rst new file mode 100644 index 00000000..569865d9 --- /dev/null +++ b/Documentation/source/changelog/20181027-added-flush-command.rst @@ -0,0 +1,6 @@ +Feature "Added flush command" +============================= + +A new command to flush indices was added. In contrast to the existing delete command, +this one will delete the whole index, while the existing delete command only deletes +all documents within an index. diff --git a/Documentation/source/changelog/20181027-allow-multiple-identifier-on-cli.rst b/Documentation/source/changelog/20181027-allow-multiple-identifier-on-cli.rst new file mode 100644 index 00000000..bab42117 --- /dev/null +++ b/Documentation/source/changelog/20181027-allow-multiple-identifier-on-cli.rst @@ -0,0 +1,4 @@ +Feature "Allow multiple identifiers on cli" +=========================================== + +All CLI commands except a comma separated list of IDs now. diff --git a/Tests/Unit/Command/IndexCommandControllerTest.php b/Tests/Unit/Command/IndexCommandControllerTest.php index 48ddd34b..e3c1e77d 100644 --- a/Tests/Unit/Command/IndexCommandControllerTest.php +++ b/Tests/Unit/Command/IndexCommandControllerTest.php @@ -61,7 +61,7 @@ public function indexerStopsForNonAllowedTable() { $this->subject->expects($this->once()) ->method('outputLine') - ->with('No indexer found for: nonAllowedTable'); + ->with('No indexer found for: nonAllowedTable.'); $this->indexerFactory->expects($this->once()) ->method('getIndexer') ->with('nonAllowedTable') @@ -78,11 +78,14 @@ public function indexerExecutesForAllowedTable() $indexerMock = $this->getMockBuilder(TcaIndexer::class) ->disableOriginalConstructor() ->getMock(); + $indexerMock->expects($this->any()) + ->method('getIdentifier') + ->willReturn('allowedTable'); $this->subject->expects($this->never()) ->method('quit'); $this->subject->expects($this->once()) ->method('outputLine') - ->with('allowedTable was indexed.'); + ->with('Documents in indice allowedTable were indexed.'); $this->indexerFactory->expects($this->once()) ->method('getIndexer') ->with('allowedTable') @@ -99,9 +102,12 @@ public function deletionIsPossible() $indexerMock = $this->getMockBuilder(TcaIndexer::class) ->disableOriginalConstructor() ->getMock(); + $indexerMock->expects($this->any()) + ->method('getIdentifier') + ->willReturn('allowedTable'); $this->subject->expects($this->once()) ->method('outputLine') - ->with('allowedTable was deleted.'); + ->with('Documents in indice allowedTable were deleted.'); $this->indexerFactory->expects($this->once()) ->method('getIndexer') ->with('allowedTable') @@ -120,9 +126,12 @@ public function flushIsPossible() $indexerMock = $this->getMockBuilder(TcaIndexer::class) ->disableOriginalConstructor() ->getMock(); + $indexerMock->expects($this->any()) + ->method('getIdentifier') + ->willReturn('pages'); $this->subject->expects($this->once()) ->method('outputLine') - ->with('Default configured indices were deleted via pages.'); + ->with('Indice pages was deleted.'); $this->indexerFactory->expects($this->once()) ->method('getIndexer') ->with('pages') @@ -140,7 +149,7 @@ public function deletionForNonExistingIndexerDoesNotWork() { $this->subject->expects($this->once()) ->method('outputLine') - ->with('No indexer found for: nonAllowedTable'); + ->with('No indexer found for: nonAllowedTable.'); $this->indexerFactory->expects($this->once()) ->method('getIndexer') ->with('nonAllowedTable') @@ -148,4 +157,85 @@ public function deletionForNonExistingIndexerDoesNotWork() $this->subject->deleteCommand('nonAllowedTable'); } + + // As all methods use the same code base, we test the logic for multiple + // identifiers only for indexing. + + /** + * @test + */ + public function indexerExecutesForAllowedTables() + { + $indexerMock = $this->getMockBuilder(TcaIndexer::class) + ->disableOriginalConstructor() + ->getMock(); + $indexerMock->expects($this->any()) + ->method('getIdentifier') + ->will($this->onConsecutiveCalls('allowedTable', 'anotherTable')); + $this->subject->expects($this->never()) + ->method('quit'); + $this->subject->expects($this->exactly(2)) + ->method('outputLine') + ->withConsecutive( + ['Documents in indice allowedTable were indexed.'], + ['Documents in indice anotherTable were indexed.'] + ); + $this->indexerFactory->expects($this->exactly(2)) + ->method('getIndexer') + ->withConsecutive(['allowedTable'], ['anotherTable']) + ->will($this->returnValue($indexerMock)); + + $this->subject->indexCommand('allowedTable, anotherTable'); + } + + /** + * @test + */ + public function indexerSkipsEmptyIdentifier() + { + $indexerMock = $this->getMockBuilder(TcaIndexer::class) + ->disableOriginalConstructor() + ->getMock(); + $indexerMock->expects($this->any()) + ->method('getIdentifier') + ->willReturn('allowedTable'); + $this->subject->expects($this->never()) + ->method('quit'); + $this->subject->expects($this->once()) + ->method('outputLine') + ->with('Documents in indice allowedTable were indexed.'); + $this->indexerFactory->expects($this->once()) + ->method('getIndexer') + ->with('allowedTable') + ->will($this->returnValue($indexerMock)); + + $this->subject->indexCommand('allowedTable, '); + } + + /** + * @test + */ + public function indexerSkipsAndOutputsNonExistingIdentifier() + { + $indexerMock = $this->getMockBuilder(TcaIndexer::class) + ->disableOriginalConstructor() + ->getMock(); + $indexerMock->expects($this->any()) + ->method('getIdentifier') + ->willReturn('allowedTable'); + $this->subject->expects($this->never()) + ->method('quit'); + $this->subject->expects($this->exactly(2)) + ->method('outputLine') + ->withConsecutive( + ['No indexer found for: nonExisting.'], + ['Documents in indice allowedTable were indexed.'] + ); + $this->indexerFactory->expects($this->exactly(2)) + ->method('getIndexer') + ->withConsecutive(['nonExisting'], ['allowedTable']) + ->will($this->onConsecutiveCalls($this->throwException(new NoMatchingIndexerException), $this->returnValue($indexerMock))); + + $this->subject->indexCommand('nonExisting, allowedTable'); + } } From 2c6521a5659dd4c60a32b5d9a7314e86880559be Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Sat, 27 Oct 2018 13:10:59 +0200 Subject: [PATCH 27/73] TASK: Fix phpdocs and type hints --- .../Connection/Elasticsearch/IndexFactory.php | 2 +- .../Elasticsearch/MappingFactory.php | 2 +- .../TcaRelationResolvingProcessor.php | 1 + Classes/Domain/Index/AbstractIndexer.php | 2 +- Classes/Domain/Index/IndexerFactory.php | 2 +- Classes/Domain/Model/ResultItem.php | 4 +-- Classes/Domain/Model/SearchRequest.php | 30 ++++--------------- Classes/Domain/Model/SearchResult.php | 1 + Classes/Hook/DataHandler.php | 9 +++--- .../Form/Finisher/DataHandlerFinisher.php | 5 ++-- .../DataHandler/AbstractDataHandlerTest.php | 3 -- .../Functional/Indexing/PagesIndexerTest.php | 2 -- 12 files changed, 21 insertions(+), 42 deletions(-) diff --git a/Classes/Connection/Elasticsearch/IndexFactory.php b/Classes/Connection/Elasticsearch/IndexFactory.php index 685d6ffd..20f5b1b1 100644 --- a/Classes/Connection/Elasticsearch/IndexFactory.php +++ b/Classes/Connection/Elasticsearch/IndexFactory.php @@ -68,7 +68,7 @@ public function __construct(ConfigurationContainerInterface $configuration) */ public function getIndexName(): string { - return (string)$this->configuration->get('connections.elasticsearch.index'); + return $this->configuration->get('connections.elasticsearch.index'); } /** diff --git a/Classes/Connection/Elasticsearch/MappingFactory.php b/Classes/Connection/Elasticsearch/MappingFactory.php index 5579cd2e..abaf62f7 100644 --- a/Classes/Connection/Elasticsearch/MappingFactory.php +++ b/Classes/Connection/Elasticsearch/MappingFactory.php @@ -50,7 +50,7 @@ public function __construct(ConfigurationContainerInterface $configuration) * @param string $documentType * @return \Elastica\Type\Mapping */ - public function getMapping(\Elastica\Type $type, $documentType = null): \Elastica\Type\Mapping + public function getMapping(\Elastica\Type $type, string $documentType = null): \Elastica\Type\Mapping { $mapping = new \Elastica\Type\Mapping(); $mapping->setType($type); diff --git a/Classes/DataProcessing/TcaRelationResolvingProcessor.php b/Classes/DataProcessing/TcaRelationResolvingProcessor.php index b0ffce8a..410a2e1d 100644 --- a/Classes/DataProcessing/TcaRelationResolvingProcessor.php +++ b/Classes/DataProcessing/TcaRelationResolvingProcessor.php @@ -58,6 +58,7 @@ public function __construct( * @param array $record * @param array $configuration * @return array + * @throws \InvalidArgumentException If _table is not configured. */ public function processData(array $record, array $configuration): array { diff --git a/Classes/Domain/Index/AbstractIndexer.php b/Classes/Domain/Index/AbstractIndexer.php index afe61e92..9057f90d 100644 --- a/Classes/Domain/Index/AbstractIndexer.php +++ b/Classes/Domain/Index/AbstractIndexer.php @@ -145,7 +145,7 @@ public function deleteDocuments() /** * @return \Generator */ - protected function getRecordGenerator() + protected function getRecordGenerator(): \Generator { $offset = 0; $limit = $this->getLimit(); diff --git a/Classes/Domain/Index/IndexerFactory.php b/Classes/Domain/Index/IndexerFactory.php index 68f3771f..ca3051bd 100644 --- a/Classes/Domain/Index/IndexerFactory.php +++ b/Classes/Domain/Index/IndexerFactory.php @@ -75,7 +75,7 @@ public function getIndexer(string $identifier): IndexerInterface /** * @param string $indexerClass * @param string $identifier - * @return \Codappix\SearchCore\Domain\Index\IndexerInterface + * @return IndexerInterface * @throws NoMatchingIndexerException */ protected function buildIndexer(string $indexerClass, string $identifier): IndexerInterface diff --git a/Classes/Domain/Model/ResultItem.php b/Classes/Domain/Model/ResultItem.php index 324ffd4d..0230fe65 100644 --- a/Classes/Domain/Model/ResultItem.php +++ b/Classes/Domain/Model/ResultItem.php @@ -2,8 +2,6 @@ namespace Codappix\SearchCore\Domain\Model; -use Codappix\SearchCore\Connection\ResultItemInterface; - /* * Copyright (C) 2017 Daniel Siepmann * @@ -23,6 +21,8 @@ * 02110-1301, USA. */ +use Codappix\SearchCore\Connection\ResultItemInterface; + class ResultItem implements ResultItemInterface { /** diff --git a/Classes/Domain/Model/SearchRequest.php b/Classes/Domain/Model/SearchRequest.php index 787a936f..17ef1979 100644 --- a/Classes/Domain/Model/SearchRequest.php +++ b/Classes/Domain/Model/SearchRequest.php @@ -24,6 +24,7 @@ use Codappix\SearchCore\Connection\ConnectionInterface; use Codappix\SearchCore\Connection\FacetRequestInterface; use Codappix\SearchCore\Connection\SearchRequestInterface; +use Codappix\SearchCore\Connection\SearchResultInterface; use Codappix\SearchCore\Domain\Search\SearchService; use Codappix\SearchCore\Utility\ArrayUtility as CustomArrayUtility; use TYPO3\CMS\Core\Utility\ArrayUtility; @@ -158,12 +159,12 @@ public function setSearchService(SearchService $searchService) $this->searchService = $searchService; } + // Extbase QueryInterface + // Current implementation covers only paginate widget support. + /** - * Extbase QueryInterface - * Current implementation covers only paginate widget support. - * * @param bool $returnRawQueryResult - * @return array|\Codappix\SearchCore\Connection\SearchResultInterface|\TYPO3\CMS\Extbase\Persistence\QueryResultInterface + * @return SearchResultInterface * @throws \InvalidArgumentException */ public function execute($returnRawQueryResult = false) @@ -223,7 +224,6 @@ public function getOffset() } /** - * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\SourceInterface|void * @throws \BadMethodCallException */ public function getSource() @@ -233,7 +233,6 @@ public function getSource() /** * @param array $orderings - * @return \TYPO3\CMS\Extbase\Persistence\QueryInterface|void * @throws \BadMethodCallException */ public function setOrderings(array $orderings) @@ -243,7 +242,6 @@ public function setOrderings(array $orderings) /** * @param \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ConstraintInterface $constraint - * @return \TYPO3\CMS\Extbase\Persistence\QueryInterface|void * @throws \BadMethodCallException */ public function matching($constraint) @@ -253,7 +251,6 @@ public function matching($constraint) /** * @param mixed $constraint1 - * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\AndInterface|void * @throws \BadMethodCallException */ public function logicalAnd($constraint1) @@ -263,7 +260,6 @@ public function logicalAnd($constraint1) /** * @param mixed $constraint1 - * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\OrInterface|void * @throws \BadMethodCallException */ public function logicalOr($constraint1) @@ -273,7 +269,6 @@ public function logicalOr($constraint1) /** * @param \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ConstraintInterface $constraint - * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\NotInterface|void * @throws \BadMethodCallException */ public function logicalNot(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\ConstraintInterface $constraint) @@ -285,7 +280,6 @@ public function logicalNot(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\Constraint * @param string $propertyName * @param mixed $operand * @param bool $caseSensitive - * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface|void * @throws \BadMethodCallException */ public function equals($propertyName, $operand, $caseSensitive = true) @@ -297,7 +291,6 @@ public function equals($propertyName, $operand, $caseSensitive = true) * @param string $propertyName * @param string $operand * @param bool $caseSensitive - * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface|void * @throws \BadMethodCallException */ public function like($propertyName, $operand, $caseSensitive = true) @@ -308,7 +301,6 @@ public function like($propertyName, $operand, $caseSensitive = true) /** * @param string $propertyName * @param mixed $operand - * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface|void * @throws \BadMethodCallException */ public function contains($propertyName, $operand) @@ -319,7 +311,6 @@ public function contains($propertyName, $operand) /** * @param string $propertyName * @param mixed $operand - * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface|void * @throws \BadMethodCallException */ public function in($propertyName, $operand) @@ -330,7 +321,6 @@ public function in($propertyName, $operand) /** * @param string $propertyName * @param mixed $operand - * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface|void * @throws \BadMethodCallException */ public function lessThan($propertyName, $operand) @@ -341,7 +331,6 @@ public function lessThan($propertyName, $operand) /** * @param string $propertyName * @param mixed $operand - * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface|void * @throws \BadMethodCallException */ public function lessThanOrEqual($propertyName, $operand) @@ -352,7 +341,6 @@ public function lessThanOrEqual($propertyName, $operand) /** * @param string $propertyName * @param mixed $operand - * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface|void * @throws \BadMethodCallException */ public function greaterThan($propertyName, $operand) @@ -363,7 +351,6 @@ public function greaterThan($propertyName, $operand) /** * @param string $propertyName * @param mixed $operand - * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface|void * @throws \BadMethodCallException */ public function greaterThanOrEqual($propertyName, $operand) @@ -372,7 +359,6 @@ public function greaterThanOrEqual($propertyName, $operand) } /** - * @return string|void * @throws \BadMethodCallException */ public function getType() @@ -390,7 +376,6 @@ public function setQuerySettings(\TYPO3\CMS\Extbase\Persistence\Generic\QuerySet } /** - * @return \TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface|void * @throws \BadMethodCallException */ public function getQuerySettings() @@ -399,7 +384,6 @@ public function getQuerySettings() } /** - * @return integer|void * @throws \BadMethodCallException */ public function count() @@ -408,7 +392,6 @@ public function count() } /** - * @return array|void * @throws \BadMethodCallException */ public function getOrderings() @@ -417,7 +400,6 @@ public function getOrderings() } /** - * @return null|\TYPO3\CMS\Extbase\Persistence\Generic\Qom\ConstraintInterface|void * @throws \BadMethodCallException */ public function getConstraint() @@ -427,7 +409,6 @@ public function getConstraint() /** * @param string $propertyName - * @return bool|void * @throws \BadMethodCallException */ public function isEmpty($propertyName) @@ -445,7 +426,6 @@ public function setSource(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\SourceInter } /** - * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\Statement|void * @throws \BadMethodCallException */ public function getStatement() diff --git a/Classes/Domain/Model/SearchResult.php b/Classes/Domain/Model/SearchResult.php index a4f494db..97a12fbf 100644 --- a/Classes/Domain/Model/SearchResult.php +++ b/Classes/Domain/Model/SearchResult.php @@ -21,6 +21,7 @@ * 02110-1301, USA. */ +use Codappix\SearchCore\Connection\ResultItemInterface; use Codappix\SearchCore\Connection\SearchResultInterface; /** diff --git a/Classes/Hook/DataHandler.php b/Classes/Hook/DataHandler.php index 3015cc0f..8f6b8c92 100644 --- a/Classes/Hook/DataHandler.php +++ b/Classes/Hook/DataHandler.php @@ -22,11 +22,12 @@ */ 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\Logger; use TYPO3\CMS\Core\Log\LogManager; +use TYPO3\CMS\Core\Log\Logger; use TYPO3\CMS\Core\SingletonInterface as Singleton; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Extbase\Object\ObjectManager; @@ -93,7 +94,7 @@ public function processCmdmap_deleteAction(string $table, string $uid): bool /** * @param CoreDataHandler $dataHandler * @return void - * @throws \Codappix\SearchCore\Domain\Index\NoMatchingIndexerException + * @throws NoMatchingIndexerException */ public function processDatamap_afterAllOperations(CoreDataHandler $dataHandler) { @@ -119,7 +120,7 @@ public function processDatamap_afterAllOperations(CoreDataHandler $dataHandler) * @param array $parameters * @param CoreDataHandler $dataHandler * @return void - * @throws \Codappix\SearchCore\Domain\Index\NoMatchingIndexerException + * @throws NoMatchingIndexerException */ public function clearCachePostProc(array $parameters, CoreDataHandler $dataHandler) { @@ -143,7 +144,7 @@ public function clearCachePostProc(array $parameters, CoreDataHandler $dataHandl * @param string $table * @param integer $uid * @return bool - * @throws \Codappix\SearchCore\Domain\Index\NoMatchingIndexerException + * @throws NoMatchingIndexerException */ protected function processRecord(string $table, int $uid): bool { diff --git a/Classes/Integration/Form/Finisher/DataHandlerFinisher.php b/Classes/Integration/Form/Finisher/DataHandlerFinisher.php index ee49649f..c98660f2 100644 --- a/Classes/Integration/Form/Finisher/DataHandlerFinisher.php +++ b/Classes/Integration/Form/Finisher/DataHandlerFinisher.php @@ -21,6 +21,7 @@ * 02110-1301, USA. */ +use Codappix\SearchCore\Domain\Index\NoMatchingIndexerException; use TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher; use TYPO3\CMS\Form\Domain\Finishers\Exception\FinisherException; @@ -48,9 +49,9 @@ class DataHandlerFinisher extends AbstractFinisher ]; /** - * @return null|string|void + * @return void * @throws FinisherException - * @throws \Codappix\SearchCore\Domain\Index\NoMatchingIndexerException + * @throws NoMatchingIndexerException */ protected function executeInternal() { diff --git a/Tests/Functional/Hooks/DataHandler/AbstractDataHandlerTest.php b/Tests/Functional/Hooks/DataHandler/AbstractDataHandlerTest.php index 0717cc76..9da72f09 100644 --- a/Tests/Functional/Hooks/DataHandler/AbstractDataHandlerTest.php +++ b/Tests/Functional/Hooks/DataHandler/AbstractDataHandlerTest.php @@ -36,9 +36,6 @@ abstract class AbstractDataHandlerTest extends AbstractFunctionalTestCase */ protected $subject; - /** - * @throws \Doctrine\DBAL\DBALException - */ public function setUp() { parent::setUp(); diff --git a/Tests/Functional/Indexing/PagesIndexerTest.php b/Tests/Functional/Indexing/PagesIndexerTest.php index 3a080ea6..08821e5d 100644 --- a/Tests/Functional/Indexing/PagesIndexerTest.php +++ b/Tests/Functional/Indexing/PagesIndexerTest.php @@ -67,8 +67,6 @@ public function pagesContainAllAdditionalInformation() * @test * @dataProvider rootLineDataSets * @param string $dataSetPath - * @throws \Codappix\SearchCore\Domain\Index\NoMatchingIndexerException - * @throws \TYPO3\TestingFramework\Core\Exception */ public function rootLineIsRespectedDuringIndexing($dataSetPath) { From 5d5af73705af83fef3a10e67ddfba4489a6a33dd Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Sat, 27 Oct 2018 13:11:39 +0200 Subject: [PATCH 28/73] TASK: Add missing license comments in PHP files --- Classes/Domain/Search/CachedSearchService.php | 19 +++++++++++++++++++ .../Search/MissingAttributeException.php | 19 +++++++++++++++++++ .../Hook/Filter/FrontendUserAccessFilter.php | 19 +++++++++++++++++++ 3 files changed, 57 insertions(+) diff --git a/Classes/Domain/Search/CachedSearchService.php b/Classes/Domain/Search/CachedSearchService.php index b0a6dffe..0976521e 100644 --- a/Classes/Domain/Search/CachedSearchService.php +++ b/Classes/Domain/Search/CachedSearchService.php @@ -2,6 +2,25 @@ namespace Codappix\SearchCore\Domain\Search; +/* + * Copyright (C) 2018 Benjamin Serfhos + * + * 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 Codappix\SearchCore\Connection\SearchResultInterface; use TYPO3\CMS\Core\SingletonInterface; diff --git a/Classes/Domain/Search/MissingAttributeException.php b/Classes/Domain/Search/MissingAttributeException.php index 0e075ed7..f47e3695 100644 --- a/Classes/Domain/Search/MissingAttributeException.php +++ b/Classes/Domain/Search/MissingAttributeException.php @@ -2,6 +2,25 @@ namespace Codappix\SearchCore\Domain\Search; +/* + * Copyright (C) 2018 Benjamin Serfhos + * + * 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 MissingAttributeException extends \InvalidArgumentException { } diff --git a/Classes/Hook/Filter/FrontendUserAccessFilter.php b/Classes/Hook/Filter/FrontendUserAccessFilter.php index e043b0a6..fc19fecc 100644 --- a/Classes/Hook/Filter/FrontendUserAccessFilter.php +++ b/Classes/Hook/Filter/FrontendUserAccessFilter.php @@ -2,6 +2,25 @@ namespace Codappix\SearchCore\Hook\Filter; +/* + * Copyright (C) 2018 Benjamin Serfhos + * + * 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\Frontend\Authentication\FrontendUserAuthentication; /** From 140dea3cbbd695141651daa1750658d2fb0d5d2d Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Sat, 27 Oct 2018 13:15:02 +0200 Subject: [PATCH 29/73] TASK: Refactor code to use guards and decrease indentation --- Classes/Connection/Elasticsearch/Facet.php | 12 ++++--- .../Connection/Elasticsearch/SearchResult.php | 34 +++++++++++-------- Classes/Domain/Model/SearchResult.php | 11 +++--- 3 files changed, 33 insertions(+), 24 deletions(-) diff --git a/Classes/Connection/Elasticsearch/Facet.php b/Classes/Connection/Elasticsearch/Facet.php index 45aa8653..c1fb1e5d 100644 --- a/Classes/Connection/Elasticsearch/Facet.php +++ b/Classes/Connection/Elasticsearch/Facet.php @@ -99,11 +99,13 @@ public function getOptions(): array */ protected function initOptions() { - if ($this->options === null) { - $this->options = []; - foreach ($this->buckets as $bucket) { - $this->options[$bucket['key']] = new FacetOption($bucket); - } + if (is_array($this->options)) { + return; + } + + $this->options = []; + foreach ($this->buckets as $bucket) { + $this->options[$bucket['key']] = new FacetOption($bucket); } } } diff --git a/Classes/Connection/Elasticsearch/SearchResult.php b/Classes/Connection/Elasticsearch/SearchResult.php index 5773a50c..faa8e373 100644 --- a/Classes/Connection/Elasticsearch/SearchResult.php +++ b/Classes/Connection/Elasticsearch/SearchResult.php @@ -115,11 +115,13 @@ public function getCurrentCount(): int */ protected function initResults() { - if ($this->results === null) { - $this->results = []; - foreach ($this->result->getResults() as $result) { - $this->results[] = new ResultItem($result->getData(), $result->getParam('_type')); - } + if (is_array($this->results)) { + return; + } + + $this->results = []; + foreach ($this->result->getResults() as $result) { + $this->results[] = new ResultItem($result->getData(), $result->getParam('_type')); } } @@ -128,16 +130,18 @@ protected function initResults() */ protected function initFacets() { - if ($this->facets === null) { - $this->facets = []; - if ($this->result->hasAggregations()) { - foreach ($this->result->getAggregations() as $aggregationName => $aggregation) { - $this->facets[$aggregationName] = $this->objectManager->get( - Facet::class, - $aggregationName, - $aggregation - ); - } + if (is_array($this->facets)) { + return; + } + + $this->facets = []; + if ($this->result->hasAggregations()) { + foreach ($this->result->getAggregations() as $aggregationName => $aggregation) { + $this->facets[$aggregationName] = $this->objectManager->get( + Facet::class, + $aggregationName, + $aggregation + ); } } } diff --git a/Classes/Domain/Model/SearchResult.php b/Classes/Domain/Model/SearchResult.php index 97a12fbf..80b88e7a 100644 --- a/Classes/Domain/Model/SearchResult.php +++ b/Classes/Domain/Model/SearchResult.php @@ -79,10 +79,13 @@ public function getResults(): array */ protected function initResults() { - if ($this->results === null) { - foreach ($this->resultItems as $item) { - $this->results[] = new ResultItem($item['data'], $item['type']); - } + if (is_array($this->results)) { + return; + } + + $this->results = []; + foreach ($this->resultItems as $item) { + $this->results[] = new ResultItem($item['data'], $item['type']); } } From 30746038c3497c4caa8c08fc7bb7e12498cd8580 Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Sat, 27 Oct 2018 13:15:29 +0200 Subject: [PATCH 30/73] TASK: Use same order within all files for plugins --- .../Mod/Wizards/NewContentElement.tsconfig | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/Configuration/TSconfig/Page/Mod/Wizards/NewContentElement.tsconfig b/Configuration/TSconfig/Page/Mod/Wizards/NewContentElement.tsconfig index 4ed2924a..e65d17b4 100644 --- a/Configuration/TSconfig/Page/Mod/Wizards/NewContentElement.tsconfig +++ b/Configuration/TSconfig/Page/Mod/Wizards/NewContentElement.tsconfig @@ -1,16 +1,5 @@ -# dummy placeholders for item groups mod.wizards.newContentElement.wizardItems.plugins { elements { - searchcore_form { - title = LLL:EXT:search_core/Resources/Private/Language/locallang_be.xlf:plugin.form.title - description = LLL:EXT:search_core/Resources/Private/Language/locallang_be.xlf:plugin.form.description - iconIdentifier = plugin-search_core-form - tt_content_defValues { - CType = list - list_type = searchcore_form - } - } - searchcore_results { title = LLL:EXT:search_core/Resources/Private/Language/locallang_be.xlf:plugin.results.title description = LLL:EXT:search_core/Resources/Private/Language/locallang_be.xlf:plugin.results.description @@ -20,5 +9,15 @@ mod.wizards.newContentElement.wizardItems.plugins { list_type = searchcore_results } } + + searchcore_form { + title = LLL:EXT:search_core/Resources/Private/Language/locallang_be.xlf:plugin.form.title + description = LLL:EXT:search_core/Resources/Private/Language/locallang_be.xlf:plugin.form.description + iconIdentifier = plugin-search_core-form + tt_content_defValues { + CType = list + list_type = searchcore_form + } + } } } From 2d9062b6e329bab8b92cad0e1f39aefe4a841ba0 Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Sat, 27 Oct 2018 13:56:29 +0200 Subject: [PATCH 31/73] TASK: Streamline phpdoc * Do not add duplicate information from PHP to phpdoc. * Do not add useless comments like "this is a constructor of class x". --- Classes/Command/IndexCommandController.php | 4 -- .../Configuration/ConfigurationContainer.php | 6 +- .../ConfigurationContainerInterface.php | 2 +- .../Configuration/ConfigurationUtility.php | 7 -- Classes/Connection/ConnectionInterface.php | 24 ------- Classes/Connection/Elasticsearch.php | 34 ---------- .../Elasticsearch/DocumentFactory.php | 13 ++-- Classes/Connection/Elasticsearch/Facet.php | 15 ----- .../Connection/Elasticsearch/FacetOption.php | 6 -- .../Connection/Elasticsearch/IndexFactory.php | 16 +---- .../Elasticsearch/MappingFactory.php | 8 --- .../Connection/Elasticsearch/SearchResult.php | 18 +----- .../Connection/Elasticsearch/TypeFactory.php | 3 - Classes/Connection/FacetInterface.php | 3 - Classes/Connection/FacetOptionInterface.php | 6 -- Classes/Connection/FacetRequestInterface.php | 4 -- Classes/Connection/ResultItemInterface.php | 4 -- Classes/Connection/SearchRequestInterface.php | 22 ------- Classes/Connection/SearchResultInterface.php | 2 - Classes/Controller/SearchController.php | 29 +++------ ...entObjectDataProcessorAdapterProcessor.php | 9 --- Classes/DataProcessing/CopyToProcessor.php | 10 --- Classes/DataProcessing/GeoPointProcessor.php | 10 --- Classes/DataProcessing/ProcessorInterface.php | 3 - Classes/DataProcessing/RemoveProcessor.php | 5 -- Classes/DataProcessing/Service.php | 7 -- .../TcaRelationResolvingProcessor.php | 14 ---- Classes/Database/Doctrine/Join.php | 11 ---- Classes/Database/Doctrine/Where.php | 11 ---- Classes/Domain/Index/AbstractIndexer.php | 58 ++--------------- Classes/Domain/Index/IndexerFactory.php | 5 -- Classes/Domain/Index/IndexerInterface.php | 14 ---- Classes/Domain/Index/TcaIndexer.php | 18 +----- .../Domain/Index/TcaIndexer/PagesIndexer.php | 30 --------- .../Index/TcaIndexer/RelationResolver.php | 31 --------- .../Index/TcaIndexer/TcaTableService.php | 62 ++---------------- .../TcaIndexer/TcaTableServiceInterface.php | 22 ------- Classes/Domain/Model/FacetRequest.php | 8 --- .../Domain/Model/QueryResultInterfaceStub.php | 6 -- Classes/Domain/Model/ResultItem.php | 22 ------- Classes/Domain/Model/SearchRequest.php | 64 ------------------- Classes/Domain/Model/SearchResult.php | 35 ---------- Classes/Domain/Search/CachedSearchService.php | 11 ---- Classes/Domain/Search/QueryFactory.php | 56 ---------------- Classes/Domain/Search/SearchService.php | 13 ---- Classes/Domain/Service/DataHandler.php | 19 ------ Classes/Hook/DataHandler.php | 20 ------ .../Hook/Filter/FrontendUserAccessFilter.php | 12 +--- .../Form/Finisher/DataHandlerFinisher.php | 1 - Classes/Utility/ArrayUtility.php | 3 - Classes/Utility/FrontendUtility.php | 3 - 51 files changed, 28 insertions(+), 791 deletions(-) diff --git a/Classes/Command/IndexCommandController.php b/Classes/Command/IndexCommandController.php index 95967137..8e1f370c 100644 --- a/Classes/Command/IndexCommandController.php +++ b/Classes/Command/IndexCommandController.php @@ -39,7 +39,6 @@ class IndexCommandController extends CommandController /** * @param IndexerFactory $factory - * @return void */ public function injectIndexerFactory(IndexerFactory $factory) { @@ -50,7 +49,6 @@ public function injectIndexerFactory(IndexerFactory $factory) * Will index all documents for the given identifiers. * * @param string $identifier Comma separated list of identifiers. - * @return void */ public function indexCommand(string $identifiers) { @@ -64,7 +62,6 @@ public function indexCommand(string $identifiers) * Will delete all indexed documents for the given identifiers. * * @param string $identifier Comma separated list of identifiers. - * @return void */ public function deleteCommand(string $identifiers) { @@ -78,7 +75,6 @@ public function deleteCommand(string $identifiers) * Will delete the full index for given identifiers. * * @param string $identifier Comma separated list of identifiers. - * @return void */ public function flushCommand(string $identifiers = 'pages') { diff --git a/Classes/Configuration/ConfigurationContainer.php b/Classes/Configuration/ConfigurationContainer.php index 1713e717..476c94e5 100644 --- a/Classes/Configuration/ConfigurationContainer.php +++ b/Classes/Configuration/ConfigurationContainer.php @@ -39,8 +39,6 @@ class ConfigurationContainer implements ConfigurationContainerInterface /** * Inject settings via ConfigurationManager. - * - * @param ConfigurationManagerInterface $configurationManager */ public function injectConfigurationManager(ConfigurationManagerInterface $configurationManager) { @@ -83,8 +81,8 @@ public function getIfExists(string $path) } /** - * @param string $path - * @return mixed + * @param string $path In dot notation. + * @return mixed|null Null if no entry was found. */ protected function getValueByPath(string $path) { diff --git a/Classes/Configuration/ConfigurationContainerInterface.php b/Classes/Configuration/ConfigurationContainerInterface.php index dec7f674..6d2caeca 100644 --- a/Classes/Configuration/ConfigurationContainerInterface.php +++ b/Classes/Configuration/ConfigurationContainerInterface.php @@ -42,7 +42,7 @@ public function get(string $path); * Same as get but will not throw an exception but return null. * * @param string $path In dot notation. - * @return mixed|null + * @return mixed|null Null if it does not exist. */ public function getIfExists(string $path); } diff --git a/Classes/Configuration/ConfigurationUtility.php b/Classes/Configuration/ConfigurationUtility.php index eb391ca3..f407ff96 100644 --- a/Classes/Configuration/ConfigurationUtility.php +++ b/Classes/Configuration/ConfigurationUtility.php @@ -28,10 +28,6 @@ class ConfigurationUtility { /** * Will parse all entries, recursive as fluid template, with request variable set to $searchRequest. - * - * @param SearchRequestInterface $searchRequest - * @param array $array - * @return array */ public function replaceArrayValuesWithRequestContent(SearchRequestInterface $searchRequest, array $array): array { @@ -53,9 +49,6 @@ public function replaceArrayValuesWithRequestContent(SearchRequestInterface $sea /** * Will check all entries, whether they have a condition and filter entries out, where condition is false. * Also will remove condition in the end. - * - * @param array $entries - * @return array */ public function filterByCondition(array $entries): array { diff --git a/Classes/Connection/ConnectionInterface.php b/Classes/Connection/ConnectionInterface.php index bad861cb..9480d041 100644 --- a/Classes/Connection/ConnectionInterface.php +++ b/Classes/Connection/ConnectionInterface.php @@ -30,19 +30,11 @@ interface ConnectionInterface { /** * Will add a new document. - * - * @param string $documentType - * @param array $document - * @return void */ public function addDocument(string $documentType, array $document); /** * Add the given documents. - * - * @param string $documentType - * @param array $documents - * @return void */ public function addDocuments(string $documentType, array $documents); @@ -50,10 +42,6 @@ public function addDocuments(string $documentType, array $documents); * Will update an existing document. * * NOTE: Batch updating is not yet supported. - * - * @param string $documentType - * @param array $document - * @return void */ public function updateDocument(string $documentType, array $document); @@ -61,33 +49,21 @@ public function updateDocument(string $documentType, array $document); * Will remove an existing document. * * NOTE: Batch deleting is not yet supported. - * - * @param string $documentType - * @param string $identifier - * @return void */ public function deleteDocument(string $documentType, string $identifier); /** * Search by given request and return result. - * - * @param SearchRequestInterface $searchRequest - * @return SearchResultInterface */ public function search(SearchRequestInterface $searchRequest): SearchResultInterface; /** * Will delete the whole index / db. - * - * @return void */ public function deleteIndex(); /** * Will delete the index / db of defined document type. - * - * @param Query $query - * @return void */ public function deleteIndexByQuery(Query $query); } diff --git a/Classes/Connection/Elasticsearch.php b/Classes/Connection/Elasticsearch.php index f5bc5d23..b77253b5 100644 --- a/Classes/Connection/Elasticsearch.php +++ b/Classes/Connection/Elasticsearch.php @@ -114,10 +114,6 @@ public function __construct( $this->queryFactory = $queryFactory; } - /** - * @param string $documentType - * @param array $document - */ public function addDocument(string $documentType, array $document) { $this->withType( @@ -128,10 +124,6 @@ function ($type) use ($documentType, $document) { ); } - /** - * @param string $documentType - * @param string $identifier - */ public function deleteDocument(string $documentType, string $identifier) { try { @@ -149,10 +141,6 @@ function ($type) use ($identifier) { } } - /** - * @param string $documentType - * @param array $document - */ public function updateDocument(string $documentType, array $document) { $this->withType( @@ -163,10 +151,6 @@ function ($type) use ($documentType, $document) { ); } - /** - * @param string $documentType - * @param array $documents - */ public function addDocuments(string $documentType, array $documents) { $this->withType( @@ -177,9 +161,6 @@ function ($type) use ($documentType, $documents) { ); } - /** - * @return void - */ public function deleteIndex() { $index = $this->connection->getClient()->getIndex($this->indexFactory->getIndexName()); @@ -195,10 +176,6 @@ public function deleteIndex() $index->delete(); } - /** - * @param Query $query - * @return void - */ public function deleteIndexByQuery(Query $query) { $index = $this->connection->getClient()->getIndex($this->indexFactory->getIndexName()); @@ -218,9 +195,6 @@ public function deleteIndexByQuery(Query $query) /** * Execute given callback with Elastica Type based on provided documentType - * - * @param string $documentType - * @param callable $callback */ protected function withType(string $documentType, callable $callback) { @@ -236,10 +210,6 @@ protected function withType(string $documentType, callable $callback) $type->getIndex()->refresh(); } - /** - * @param SearchRequestInterface $searchRequest - * @return SearchResultInterface - */ public function search(SearchRequestInterface $searchRequest): SearchResultInterface { $this->logger->debug('Search for', [$searchRequest->getSearchTerm()]); @@ -251,10 +221,6 @@ public function search(SearchRequestInterface $searchRequest): SearchResultInter return $this->objectManager->get(SearchResult::class, $searchRequest, $search->search()); } - /** - * @param string $documentType - * @return \Elastica\Type - */ protected function getType($documentType): \Elastica\Type { return $this->typeFactory->getType( diff --git a/Classes/Connection/Elasticsearch/DocumentFactory.php b/Classes/Connection/Elasticsearch/DocumentFactory.php index 086fff3b..ca90ebed 100644 --- a/Classes/Connection/Elasticsearch/DocumentFactory.php +++ b/Classes/Connection/Elasticsearch/DocumentFactory.php @@ -46,17 +46,14 @@ public function injectLogger(\TYPO3\CMS\Core\Log\LogManager $logManager) /** * Creates document from document. * - * @param string $documentType - * @param array $document - * @return \Elastica\Document - * @throws \Exception + * @throws \InvalidArgumentException If no search identifier was provided. */ public function getDocument(string $documentType, array $document): \Elastica\Document { // TODO: Use DocumentType for further configuration. if (!isset($document['search_identifier'])) { - throw new \Exception('No search_identifier provided for document.', 1481194385); + throw new \InvalidArgumentException('No search_identifier provided for document.', 1481194385); } $identifier = $document['search_identifier']; @@ -70,10 +67,8 @@ public function getDocument(string $documentType, array $document): \Elastica\Do /** * Creates documents based on documents. - * @param string $documentType - * @param array $documents - * @return array - * @throws \Exception + * + * @throws \InvalidArgumentException If no search identifier was provided. */ public function getDocuments(string $documentType, array $documents): array { diff --git a/Classes/Connection/Elasticsearch/Facet.php b/Classes/Connection/Elasticsearch/Facet.php index c1fb1e5d..44646976 100644 --- a/Classes/Connection/Elasticsearch/Facet.php +++ b/Classes/Connection/Elasticsearch/Facet.php @@ -46,12 +46,6 @@ class Facet implements FacetInterface */ protected $options; - /** - * Facet constructor. - * @param string $name - * @param array $aggregation - * @param ConfigurationContainerInterface $configuration - */ public function __construct(string $name, array $aggregation, ConfigurationContainerInterface $configuration) { $this->name = $name; @@ -66,17 +60,11 @@ public function __construct(string $name, array $aggregation, ConfigurationConta } } - /** - * @return string - */ public function getName(): string { return $this->name; } - /** - * @return string - */ public function getField(): string { return $this->field; @@ -94,9 +82,6 @@ public function getOptions(): array return $this->options; } - /** - * @return void - */ protected function initOptions() { if (is_array($this->options)) { diff --git a/Classes/Connection/Elasticsearch/FacetOption.php b/Classes/Connection/Elasticsearch/FacetOption.php index b2fd1408..d661c4c0 100644 --- a/Classes/Connection/Elasticsearch/FacetOption.php +++ b/Classes/Connection/Elasticsearch/FacetOption.php @@ -40,9 +40,6 @@ class FacetOption implements FacetOptionInterface */ protected $count = 0; - /** - * @param array $bucket - */ public function __construct(array $bucket) { $this->name = $bucket['key']; @@ -50,9 +47,6 @@ public function __construct(array $bucket) $this->count = $bucket['doc_count']; } - /** - * @return string - */ public function getName(): string { return $this->name; diff --git a/Classes/Connection/Elasticsearch/IndexFactory.php b/Classes/Connection/Elasticsearch/IndexFactory.php index 20f5b1b1..2482c0eb 100644 --- a/Classes/Connection/Elasticsearch/IndexFactory.php +++ b/Classes/Connection/Elasticsearch/IndexFactory.php @@ -63,8 +63,6 @@ public function __construct(ConfigurationContainerInterface $configuration) /** * Get the index name from the typoscript settings. - * - * @return string */ public function getIndexName(): string { @@ -72,11 +70,7 @@ public function getIndexName(): string } /** - * Get an index bases on TYPO3 table name. - * - * @param Connection $connection - * @param string $documentType - * @return \Elastica\Index + * Get an index based on TYPO3 table name. */ public function getIndex(Connection $connection, string $documentType): \Elastica\Index { @@ -92,10 +86,6 @@ public function getIndex(Connection $connection, string $documentType): \Elastic return $index; } - /** - * @param string $documentType - * @return array - */ protected function getConfigurationFor(string $documentType): array { try { @@ -117,10 +107,6 @@ protected function getConfigurationFor(string $documentType): array } } - /** - * @param array $analyzer - * @return array - */ protected function prepareAnalyzerConfiguration(array $analyzer): array { $fieldsToExplode = ['char_filter', 'filter', 'word_list']; diff --git a/Classes/Connection/Elasticsearch/MappingFactory.php b/Classes/Connection/Elasticsearch/MappingFactory.php index abaf62f7..8076593f 100644 --- a/Classes/Connection/Elasticsearch/MappingFactory.php +++ b/Classes/Connection/Elasticsearch/MappingFactory.php @@ -45,10 +45,6 @@ public function __construct(ConfigurationContainerInterface $configuration) /** * Get an mapping based on type. - * - * @param \Elastica\Type $type - * @param string $documentType - * @return \Elastica\Type\Mapping */ public function getMapping(\Elastica\Type $type, string $documentType = null): \Elastica\Type\Mapping { @@ -61,10 +57,6 @@ public function getMapping(\Elastica\Type $type, string $documentType = null): \ return $mapping; } - /** - * @param string $identifier - * @return array - */ protected function getConfiguration(string $identifier): array { try { diff --git a/Classes/Connection/Elasticsearch/SearchResult.php b/Classes/Connection/Elasticsearch/SearchResult.php index faa8e373..1704f2d7 100644 --- a/Classes/Connection/Elasticsearch/SearchResult.php +++ b/Classes/Connection/Elasticsearch/SearchResult.php @@ -63,13 +63,6 @@ class SearchResult implements SearchResultInterface */ protected $objectManager; - /** - * SearchResult constructor. - * - * @param SearchRequestInterface $searchRequest - * @param \Elastica\ResultSet $result - * @param ObjectManagerInterface $objectManager - */ public function __construct( SearchRequestInterface $searchRequest, \Elastica\ResultSet $result, @@ -102,17 +95,11 @@ public function getFacets(): array return $this->facets; } - /** - * @return integer - */ public function getCurrentCount(): int { return $this->result->count(); } - /** - * @return void - */ protected function initResults() { if (is_array($this->results)) { @@ -125,9 +112,6 @@ protected function initResults() } } - /** - * @return void - */ protected function initFacets() { if (is_array($this->facets)) { @@ -207,7 +191,7 @@ public function rewind() } /** - * @return SearchRequestInterface|\TYPO3\CMS\Extbase\Persistence\QueryInterface + * @return SearchRequestInterface */ public function getQuery() { diff --git a/Classes/Connection/Elasticsearch/TypeFactory.php b/Classes/Connection/Elasticsearch/TypeFactory.php index ccb8cb82..d14fb681 100644 --- a/Classes/Connection/Elasticsearch/TypeFactory.php +++ b/Classes/Connection/Elasticsearch/TypeFactory.php @@ -32,9 +32,6 @@ class TypeFactory implements Singleton { /** * Get an index bases on TYPO3 table name. - * @param \Elastica\Index $index - * @param string $documentType - * @return \Elastica\Type */ public function getType(\Elastica\Index $index, string $documentType): \Elastica\Type { diff --git a/Classes/Connection/FacetInterface.php b/Classes/Connection/FacetInterface.php index f95b5e5a..de22f62c 100644 --- a/Classes/Connection/FacetInterface.php +++ b/Classes/Connection/FacetInterface.php @@ -26,9 +26,6 @@ */ interface FacetInterface { - /** - * @return string - */ public function getName(): string; /** diff --git a/Classes/Connection/FacetOptionInterface.php b/Classes/Connection/FacetOptionInterface.php index 401699a7..7c07a5d6 100644 --- a/Classes/Connection/FacetOptionInterface.php +++ b/Classes/Connection/FacetOptionInterface.php @@ -29,23 +29,17 @@ interface FacetOptionInterface /** * Returns the name of this option. Equivalent * to value used for filtering. - * - * @return string */ public function getName(): string; /** * If a pre-rendered name is provided, this will be returned. * Otherwise it's the same as getName(). - * - * @return string */ public function getDisplayName(): string; /** * Returns the number of found results for this option. - * - * @return integer */ public function getCount(): int; } diff --git a/Classes/Connection/FacetRequestInterface.php b/Classes/Connection/FacetRequestInterface.php index 2a8e7833..a4634f7d 100644 --- a/Classes/Connection/FacetRequestInterface.php +++ b/Classes/Connection/FacetRequestInterface.php @@ -29,15 +29,11 @@ interface FacetRequestInterface /** * The identifier of the facet, used as key in arrays and to get the facet * from search request, etc. - * - * @return string */ public function getIdentifier(): string; /** * The config to use for facet building. - * - * @return array */ public function getConfig(): array; } diff --git a/Classes/Connection/ResultItemInterface.php b/Classes/Connection/ResultItemInterface.php index f1f105b7..4483f9de 100644 --- a/Classes/Connection/ResultItemInterface.php +++ b/Classes/Connection/ResultItemInterface.php @@ -32,8 +32,6 @@ interface ResultItemInterface extends \ArrayAccess * Provide key/column/field => data. * * Used e.g. for dataprocessing. - * - * @return array */ public function getPlainData(): array; @@ -42,8 +40,6 @@ public function getPlainData(): array; * * That should make it easier to differentiate if multiple * types are returned for one query. - * - * @return string */ public function getType(): string; } diff --git a/Classes/Connection/SearchRequestInterface.php b/Classes/Connection/SearchRequestInterface.php index c49adc8a..d6778862 100644 --- a/Classes/Connection/SearchRequestInterface.php +++ b/Classes/Connection/SearchRequestInterface.php @@ -28,31 +28,15 @@ interface SearchRequestInterface extends QueryInterface { /** * Returns the actual string the user searched for. - * - * @return string */ public function getSearchTerm(): string; - /** - * @return bool - */ public function hasFilter(): bool; - /** - * @return array - */ public function getFilter(): array; - /** - * @param array $filter - * @return void - */ public function setFilter(array $filter); - /** - * @param FacetRequestInterface $facet - * @return void - */ public function addFacet(FacetRequestInterface $facet); /** @@ -63,18 +47,12 @@ public function getFacets(): array; /** * Workaround for paginate widget support which will * use the request to build another search. - * - * @param ConnectionInterface $connection - * @return void */ public function setConnection(ConnectionInterface $connection); /** * Workaround for paginate widget support which will * use the request to build another search. - * - * @param SearchService $searchService - * @return void */ public function setSearchService(SearchService $searchService); } diff --git a/Classes/Connection/SearchResultInterface.php b/Classes/Connection/SearchResultInterface.php index 83af1b35..692dae31 100644 --- a/Classes/Connection/SearchResultInterface.php +++ b/Classes/Connection/SearchResultInterface.php @@ -42,8 +42,6 @@ public function getFacets(): array; /** * Returns the number of results in current result - * - * @return integer */ public function getCurrentCount(): int; } diff --git a/Classes/Controller/SearchController.php b/Classes/Controller/SearchController.php index f4f9299d..3f125046 100644 --- a/Classes/Controller/SearchController.php +++ b/Classes/Controller/SearchController.php @@ -45,10 +45,6 @@ public function __construct(CachedSearchService $searchService) parent::__construct(); } - /** - * @throws \TYPO3\CMS\Extbase\Mvc\Exception\NoSuchArgumentException - * @return void - */ public function initializeSearchAction() { if (isset($this->settings['searching']['mode']) @@ -68,31 +64,22 @@ public function initializeSearchAction() } /** - * Action: Search form - * - * @param SearchRequest $searchRequest - * @return void + * Display results and deliver original request and result to view. */ public function formAction(SearchRequest $searchRequest = null) { - $searchResult = null; - if ($searchRequest !== null) { - $searchResult = $this->searchService->search($searchRequest); - } - - $this->view->assignMultiple([ - 'searchRequest' => $searchRequest, - 'searchResult' => $searchResult, - ]); + $this->action($searchRequest); } /** - * Action: Display list results and deliver original request and result to view. - * - * @param SearchRequest $searchRequest - * @return void + * Display results and deliver original request and result to view. */ public function resultsAction(SearchRequest $searchRequest = null) + { + $this->action($searchRequest); + } + + private function action(SearchRequest $searchRequest = null) { $searchResult = null; if ($searchRequest !== null) { diff --git a/Classes/DataProcessing/ContentObjectDataProcessorAdapterProcessor.php b/Classes/DataProcessing/ContentObjectDataProcessorAdapterProcessor.php index cf440751..d0425a90 100644 --- a/Classes/DataProcessing/ContentObjectDataProcessorAdapterProcessor.php +++ b/Classes/DataProcessing/ContentObjectDataProcessorAdapterProcessor.php @@ -35,20 +35,11 @@ class ContentObjectDataProcessorAdapterProcessor implements ProcessorInterface */ protected $typoScriptService; - /** - * ContentObjectDataProcessorAdapterProcessor constructor. - * @param TypoScriptService $typoScriptService - */ public function __construct(TypoScriptService $typoScriptService) { $this->typoScriptService = $typoScriptService; } - /** - * @param array $data - * @param array $configuration - * @return array - */ public function processData(array $data, array $configuration): array { $dataProcessor = GeneralUtility::makeInstance($configuration['_dataProcessor']); diff --git a/Classes/DataProcessing/CopyToProcessor.php b/Classes/DataProcessing/CopyToProcessor.php index cda934cd..7cdde685 100644 --- a/Classes/DataProcessing/CopyToProcessor.php +++ b/Classes/DataProcessing/CopyToProcessor.php @@ -26,11 +26,6 @@ */ class CopyToProcessor implements ProcessorInterface { - /** - * @param array $record - * @param array $configuration - * @return array - */ public function processData(array $record, array $configuration): array { $target = []; @@ -52,11 +47,6 @@ public function processData(array $record, array $configuration): array return $record; } - /** - * @param array $target - * @param array $from - * @return void - */ protected function addArray(array &$target, array $from) { foreach ($from as $value) { diff --git a/Classes/DataProcessing/GeoPointProcessor.php b/Classes/DataProcessing/GeoPointProcessor.php index 597aacb9..15376ee2 100644 --- a/Classes/DataProcessing/GeoPointProcessor.php +++ b/Classes/DataProcessing/GeoPointProcessor.php @@ -26,11 +26,6 @@ */ class GeoPointProcessor implements ProcessorInterface { - /** - * @param array $record - * @param array $configuration - * @return array - */ public function processData(array $record, array $configuration): array { if (!$this->isApplyable($record, $configuration)) { @@ -45,11 +40,6 @@ public function processData(array $record, array $configuration): array return $record; } - /** - * @param array $record - * @param array $configuration - * @return bool - */ protected function isApplyable(array $record, array $configuration): bool { if (!isset($record[$configuration['lat']]) diff --git a/Classes/DataProcessing/ProcessorInterface.php b/Classes/DataProcessing/ProcessorInterface.php index 9bd722bf..d421fad8 100644 --- a/Classes/DataProcessing/ProcessorInterface.php +++ b/Classes/DataProcessing/ProcessorInterface.php @@ -29,9 +29,6 @@ interface ProcessorInterface /** * Processes the given data. * Also retrieves the configuration for this processor instance. - * @param array $record - * @param array $configuration - * @return array */ public function processData(array $record, array $configuration): array; } diff --git a/Classes/DataProcessing/RemoveProcessor.php b/Classes/DataProcessing/RemoveProcessor.php index beed7837..1aa31f10 100644 --- a/Classes/DataProcessing/RemoveProcessor.php +++ b/Classes/DataProcessing/RemoveProcessor.php @@ -28,11 +28,6 @@ */ class RemoveProcessor implements ProcessorInterface { - /** - * @param array $record - * @param array $configuration - * @return array - */ public function processData(array $record, array $configuration): array { if (!isset($configuration['fields'])) { diff --git a/Classes/DataProcessing/Service.php b/Classes/DataProcessing/Service.php index 18cc3eb4..8dca7ca4 100644 --- a/Classes/DataProcessing/Service.php +++ b/Classes/DataProcessing/Service.php @@ -33,10 +33,6 @@ class Service */ protected $objectManager; - /** - * Service constructor. - * @param ObjectManagerInterface $objectManager - */ public function __construct(ObjectManagerInterface $objectManager) { $this->objectManager = $objectManager; @@ -46,9 +42,6 @@ public function __construct(ObjectManagerInterface $objectManager) * Executes the dataprocessor depending on configuration and returns the result. * * @param array|string $configuration Either the full configuration or only the class name. - * @param array $data - * @param string $recordType - * @return array */ public function executeDataProcessor($configuration, array $data, string $recordType = ''): array { diff --git a/Classes/DataProcessing/TcaRelationResolvingProcessor.php b/Classes/DataProcessing/TcaRelationResolvingProcessor.php index 410a2e1d..54d90ab1 100644 --- a/Classes/DataProcessing/TcaRelationResolvingProcessor.php +++ b/Classes/DataProcessing/TcaRelationResolvingProcessor.php @@ -41,11 +41,6 @@ class TcaRelationResolvingProcessor implements ProcessorInterface */ protected $relationResolver; - /** - * TcaRelationResolvingProcessor constructor. - * @param ObjectManagerInterface $objectManager - * @param RelationResolver $relationResolver - */ public function __construct( ObjectManagerInterface $objectManager, RelationResolver $relationResolver @@ -55,9 +50,6 @@ public function __construct( } /** - * @param array $record - * @param array $configuration - * @return array * @throws \InvalidArgumentException If _table is not configured. */ public function processData(array $record, array $configuration): array @@ -79,7 +71,6 @@ public function processData(array $record, array $configuration): array } /** - * @param array $configuration * @throws \InvalidArgumentException If _table is not configured. */ protected function initializeConfiguration(array &$configuration) @@ -95,11 +86,6 @@ protected function initializeConfiguration(array &$configuration) $configuration['excludeFields'] = GeneralUtility::trimExplode(',', $configuration['excludeFields'], true); } - /** - * @param array $record - * @param array $configuration - * @return array - */ protected function getRecordToProcess(array $record, array $configuration): array { if ($configuration['excludeFields'] === []) { diff --git a/Classes/Database/Doctrine/Join.php b/Classes/Database/Doctrine/Join.php index 99bcaca4..928d9632 100644 --- a/Classes/Database/Doctrine/Join.php +++ b/Classes/Database/Doctrine/Join.php @@ -33,28 +33,17 @@ class Join */ protected $condition = ''; - /** - * Join constructor. - * @param string $table - * @param string $condition - */ public function __construct(string $table, string $condition) { $this->table = $table; $this->condition = $condition; } - /** - * @return string - */ public function getTable(): string { return $this->table; } - /** - * @return string - */ public function getCondition(): string { return $this->condition; diff --git a/Classes/Database/Doctrine/Where.php b/Classes/Database/Doctrine/Where.php index 21ad2dfa..b02feb63 100644 --- a/Classes/Database/Doctrine/Where.php +++ b/Classes/Database/Doctrine/Where.php @@ -33,28 +33,17 @@ class Where */ protected $parameters = []; - /** - * Where constructor. - * @param string $statement - * @param array $parameters - */ public function __construct(string $statement, array $parameters) { $this->statement = $statement; $this->parameters = $parameters; } - /** - * @return string - */ public function getStatement(): string { return $this->statement; } - /** - * @return array - */ public function getParameters(): array { return $this->parameters; diff --git a/Classes/Domain/Index/AbstractIndexer.php b/Classes/Domain/Index/AbstractIndexer.php index 9057f90d..a016de02 100644 --- a/Classes/Domain/Index/AbstractIndexer.php +++ b/Classes/Domain/Index/AbstractIndexer.php @@ -65,20 +65,12 @@ public function injectLogger(\TYPO3\CMS\Core\Log\LogManager $logManager) $this->logger = $logManager->getLogger(__CLASS__); } - /** - * AbstractIndexer constructor. - * @param ConnectionInterface $connection - * @param ConfigurationContainerInterface $configuration - */ public function __construct(ConnectionInterface $connection, ConfigurationContainerInterface $configuration) { $this->connection = $connection; $this->configuration = $configuration; } - /** - * @return void - */ public function indexAllDocuments() { $this->logger->info('Start indexing'); @@ -97,10 +89,6 @@ public function indexAllDocuments() $this->logger->info('Finish indexing'); } - /** - * @param string $identifier - * @return void - */ public function indexDocument(string $identifier) { $this->logger->info('Start indexing single record.', [$identifier]); @@ -116,9 +104,6 @@ public function indexDocument(string $identifier) $this->logger->info('Finish indexing'); } - /** - * @return void - */ public function delete() { $this->logger->info('Start deletion of index.'); @@ -126,9 +111,6 @@ public function delete() $this->logger->info('Finish deletion.'); } - /** - * @return void - */ public function deleteDocuments() { $this->logger->info('Start deletion of indexed documents.'); @@ -142,26 +124,17 @@ public function deleteDocuments() $this->logger->info('Finish deletion.'); } - /** - * @return \Generator - */ protected function getRecordGenerator(): \Generator { $offset = 0; $limit = $this->getLimit(); - while (($records = $this->getRecords($offset, $limit)) !== null) { - if (!empty($records)) { - yield $records; - } + while (($records = $this->getRecords($offset, $limit)) !== []) { + yield $records; $offset += $limit; } } - /** - * @param array $record - * @return void - */ protected function prepareRecord(array &$record) { try { @@ -175,10 +148,6 @@ protected function prepareRecord(array &$record) $this->handleAbstract($record); } - /** - * @param array $record - * @return void - */ protected function generateSearchIdentifiers(array &$record) { if (!isset($record['search_document'])) { @@ -189,10 +158,6 @@ protected function generateSearchIdentifiers(array &$record) } } - /** - * @param array $record - * @return void - */ protected function handleAbstract(array &$record) { $record['search_abstract'] = ''; @@ -219,8 +184,6 @@ protected function handleAbstract(array &$record) /** * Returns the limit to use to fetch records. - * - * @return integer */ protected function getLimit(): int { @@ -238,27 +201,14 @@ public function getIdentifier(): string return $this->identifier; } - /** - * @param integer $offset - * @param integer $limit - * @return array|null - */ - abstract protected function getRecords(int $offset, int $limit); + abstract protected function getRecords(int $offset, int $limit): array; /** - * @param integer $identifier - * @return array + * @throws NoRecordFoundException If record could not be found. */ abstract protected function getRecord(int $identifier): array; - /** - * @return string - */ abstract protected function getDocumentName(): string; - /** - * @param string $identifier - * @return string - */ abstract public function getDocumentIdentifier($identifier): string; } diff --git a/Classes/Domain/Index/IndexerFactory.php b/Classes/Domain/Index/IndexerFactory.php index ca3051bd..860a4cac 100644 --- a/Classes/Domain/Index/IndexerFactory.php +++ b/Classes/Domain/Index/IndexerFactory.php @@ -55,8 +55,6 @@ public function __construct( } /** - * @param string $identifier - * @return IndexerInterface * @throws NoMatchingIndexerException */ public function getIndexer(string $identifier): IndexerInterface @@ -73,9 +71,6 @@ public function getIndexer(string $identifier): IndexerInterface } /** - * @param string $indexerClass - * @param string $identifier - * @return IndexerInterface * @throws NoMatchingIndexerException */ protected function buildIndexer(string $indexerClass, string $identifier): IndexerInterface diff --git a/Classes/Domain/Index/IndexerInterface.php b/Classes/Domain/Index/IndexerInterface.php index 3debab15..f413677d 100644 --- a/Classes/Domain/Index/IndexerInterface.php +++ b/Classes/Domain/Index/IndexerInterface.php @@ -28,45 +28,31 @@ interface IndexerInterface { /** * Fetches all documents from the indexerService and pushes it to the connection. - * - * @return void */ public function indexAllDocuments(); /** * Fetches a single document and pushes it to the connection. - * - * @param string $identifier - * @return void */ public function indexDocument(string $identifier); /** * Delete the whole index. - * - * @return void */ public function delete(); /** * Delete the whole index. - * - * @return void */ public function deleteDocuments(); /** * Receives the identifier of the indexer itself. - * - * @param string $identifier - * @return void */ public function setIdentifier(string $identifier); /** * Returnes the identifier of the indexer. - * - * @return string */ public function getIdentifier(): string; } diff --git a/Classes/Domain/Index/TcaIndexer.php b/Classes/Domain/Index/TcaIndexer.php index 69fdf989..39170efb 100644 --- a/Classes/Domain/Index/TcaIndexer.php +++ b/Classes/Domain/Index/TcaIndexer.php @@ -49,16 +49,11 @@ public function __construct( $this->tcaTableService = $tcaTableService; } - /** - * @param integer $offset - * @param integer $limit - * @return array|null - */ - protected function getRecords(int $offset, int $limit) + protected function getRecords(int $offset, int $limit): array { $records = $this->tcaTableService->getRecords($offset, $limit); if ($records === []) { - return null; + return []; } $this->tcaTableService->filterRecordsByRootLineBlacklist($records); @@ -70,8 +65,6 @@ protected function getRecords(int $offset, int $limit) } /** - * @param integer $identifier - * @return array * @throws NoRecordFoundException If record could not be found. */ protected function getRecord(int $identifier): array @@ -88,18 +81,11 @@ protected function getRecord(int $identifier): array return $record; } - /** - * @return string - */ protected function getDocumentName(): string { return $this->tcaTableService->getTableName(); } - /** - * @param string $identifier - * @return string - */ public function getDocumentIdentifier($identifier): string { return $this->getDocumentName() . '-' . $identifier; diff --git a/Classes/Domain/Index/TcaIndexer/PagesIndexer.php b/Classes/Domain/Index/TcaIndexer/PagesIndexer.php index 20ccc65c..d77465fe 100644 --- a/Classes/Domain/Index/TcaIndexer/PagesIndexer.php +++ b/Classes/Domain/Index/TcaIndexer/PagesIndexer.php @@ -60,9 +60,6 @@ public function __construct( $this->contentTableService = $contentTableService; } - /** - * @param array $record - */ protected function prepareRecord(array &$record) { parent::prepareRecord($record); @@ -86,10 +83,6 @@ protected function prepareRecord(array &$record) } } - /** - * @param integer $uid - * @return array - */ protected function fetchContentForPage(int $uid): array { if ($this->contentTableService instanceof TcaTableService) { @@ -135,29 +128,16 @@ protected function fetchContentForPage(int $uid): array ]; } - /** - * @param integer $uidOfContentElement - * @return array - */ protected function getContentElementImages(int $uidOfContentElement): array { return $this->fetchSysFileReferenceUids($uidOfContentElement, 'tt_content', 'image'); } - /** - * @param integer $uid - * @return array - */ protected function fetchMediaForPage(int $uid): array { return $this->fetchSysFileReferenceUids($uid, 'pages', 'media'); } - /** - * @param integer $uid - * @param array $pageAccess - * @return array - */ protected function fetchAccess(int $uid, array $pageAccess): array { try { @@ -194,12 +174,6 @@ protected function fetchAccess(int $uid, array $pageAccess): array return array_values($access); } - /** - * @param integer $uid - * @param string $tablename - * @param string $fieldname - * @return array - */ protected function fetchSysFileReferenceUids(int $uid, string $tablename, string $fieldname): array { $imageRelationUids = []; @@ -212,10 +186,6 @@ protected function fetchSysFileReferenceUids(int $uid, string $tablename, string return $imageRelationUids; } - /** - * @param array $contentElement - * @return string - */ protected function getContentFromContentElement(array $contentElement): string { $content = ''; diff --git a/Classes/Domain/Index/TcaIndexer/RelationResolver.php b/Classes/Domain/Index/TcaIndexer/RelationResolver.php index 7a4ac2f5..6796d13c 100644 --- a/Classes/Domain/Index/TcaIndexer/RelationResolver.php +++ b/Classes/Domain/Index/TcaIndexer/RelationResolver.php @@ -34,11 +34,6 @@ */ class RelationResolver implements Singleton { - /** - * @param TcaTableServiceInterface $service - * @param array $record - * @return array - */ public function resolveRelationsForRecord(TcaTableServiceInterface $service, array $record): array { foreach (array_keys($record) as $column) { @@ -64,11 +59,6 @@ public function resolveRelationsForRecord(TcaTableServiceInterface $service, arr return $record; } - /** - * @param string $value - * @param array $tcaColumn - * @return array - */ protected function resolveValue($value, array $tcaColumn) { if ($value === '' || $value === 'N/A') { @@ -85,10 +75,6 @@ protected function resolveValue($value, array $tcaColumn) return []; } - /** - * @param array $config - * @return boolean - */ protected function isRelation(array &$config): bool { return isset($config['foreign_table']) @@ -96,27 +82,16 @@ protected function isRelation(array &$config): bool || (isset($config['internal_type']) && strtolower($config['internal_type']) === 'db'); } - /** - * @param string $value - * @return array - */ protected function resolveForeignDbValue(string $value): array { return array_map('trim', explode(';', $value)); } - /** - * @param string $value - * @return array - */ protected function resolveInlineValue(string $value): array { return array_map('trim', explode(',', $value)); } - /** - * @return string - */ protected function getUtilityForMode(): string { if (TYPO3_MODE === 'BE') { @@ -126,12 +101,6 @@ protected function getUtilityForMode(): string return FrontendUtility::class; } - /** - * @param array $record - * @param string $column - * @param TcaTableServiceInterface $service - * @return string - */ protected function getColumnValue(array $record, string $column, TcaTableServiceInterface $service): string { $utility = GeneralUtility::makeInstance($this->getUtilityForMode()); diff --git a/Classes/Domain/Index/TcaIndexer/TcaTableService.php b/Classes/Domain/Index/TcaIndexer/TcaTableService.php index 5f69da5b..6216dae6 100644 --- a/Classes/Domain/Index/TcaIndexer/TcaTableService.php +++ b/Classes/Domain/Index/TcaIndexer/TcaTableService.php @@ -83,8 +83,6 @@ public function injectObjectManager(ObjectManagerInterface $objectManager) } /** - * @param string $tableName - * @param ConfigurationContainerInterface $configuration * @throws IndexingException */ public function __construct( @@ -103,27 +101,16 @@ public function __construct( $this->configuration = $configuration; } - /** - * @return string - */ public function getTableName(): string { return $this->tableName; } - /** - * @return string - */ public function getTableClause(): string { return $this->tableName; } - /** - * @param integer $offset - * @param integer $limit - * @return array - */ public function getRecords(int $offset, int $limit): array { $records = $this->getQuery() @@ -135,10 +122,6 @@ public function getRecords(int $offset, int $limit): array return $records ?: []; } - /** - * @param integer $identifier - * @return array - */ public function getRecord(int $identifier): array { $query = $this->getQuery(); @@ -148,10 +131,6 @@ public function getRecord(int $identifier): array return $record ?: []; } - /** - * @param array $records - * @return void - */ public function filterRecordsByRootLineBlacklist(array &$records) { $records = array_filter( @@ -162,10 +141,6 @@ function ($record) { ); } - /** - * @param array $record - * @return void - */ public function prepareRecord(array &$record) { if (isset($record[$this->tca['ctrl']['label']]) && !isset($record['search_title'])) { @@ -203,9 +178,6 @@ public function prepareRecord(array &$record) } } - /** - * @return Where - */ protected function getWhereClause(): Where { $parameters = []; @@ -228,9 +200,6 @@ protected function getWhereClause(): Where return new Where($whereClause, $parameters); } - /** - * @return array - */ protected function getFields(): array { $fields = array_merge( @@ -253,10 +222,6 @@ function ($columnName) { return $fields; } - - /** - * @return array - */ protected function getJoins(): array { if ($this->tableName === 'pages') { @@ -287,10 +252,6 @@ protected function getSystemWhereClause(): string return $whereClause; } - /** - * @param string $columnName - * @return bool - */ protected function isSystemField(string $columnName): bool { $systemFields = [ @@ -317,8 +278,7 @@ protected function isSystemField(string $columnName): bool } /** - * @param string $columnName - * @return bool + * @throws InvalidArgumentException If column does not exist. */ protected function isUserField(string $columnName): bool { @@ -327,8 +287,7 @@ protected function isUserField(string $columnName): bool } /** - * @param string $columnName - * @return bool + * @throws InvalidArgumentException If column does not exist. */ protected function isPassthroughField(string $columnName): bool { @@ -337,8 +296,7 @@ protected function isPassthroughField(string $columnName): bool } /** - * @param string $columnName - * @return array + * @throws InvalidArgumentException If column does not exist. */ public function getColumnConfig(string $columnName): array { @@ -352,9 +310,6 @@ public function getColumnConfig(string $columnName): array return $this->tca['columns'][$columnName]['config']; } - /** - * @return string - */ public function getLanguageUidColumn(): string { if (!isset($this->tca['ctrl']['languageField'])) { @@ -371,9 +326,6 @@ public function getLanguageUidColumn(): string * Also further TYPO3 mechanics are taken into account. Does a valid root * line exist, is page inside a recycler, is inherited start- endtime * excluded, etc. - * - * @param array $record - * @return bool */ protected function isRecordBlacklistedByRootline(array &$record): bool { @@ -432,7 +384,7 @@ protected function isRecordBlacklistedByRootline(array &$record): bool */ protected function isBlackListedRootLineConfigured(): bool { - return (bool)$this->configuration->getIfExists('indexing.' . $this->getTableName() . '.rootLineBlacklist'); + return $this->configuration->getIfExists('indexing.' . $this->getTableName() . '.rootLineBlacklist'); } /** @@ -448,9 +400,6 @@ protected function getBlackListedRootLine(): array ); } - /** - * @return QueryBuilder - */ public function getQuery(): QueryBuilder { $queryBuilder = $this->getDatabaseConnection()->getQueryBuilderForTable($this->getTableName()); @@ -468,9 +417,6 @@ public function getQuery(): QueryBuilder return $query; } - /** - * @return ConnectionPool - */ protected function getDatabaseConnection(): ConnectionPool { return GeneralUtility::makeInstance(ConnectionPool::class); diff --git a/Classes/Domain/Index/TcaIndexer/TcaTableServiceInterface.php b/Classes/Domain/Index/TcaIndexer/TcaTableServiceInterface.php index 6025b101..d7184d2c 100644 --- a/Classes/Domain/Index/TcaIndexer/TcaTableServiceInterface.php +++ b/Classes/Domain/Index/TcaIndexer/TcaTableServiceInterface.php @@ -35,38 +35,16 @@ public function getTableClause(): string; /** * Filter the given records by root line blacklist settings. - * @param array $records - * @return void */ public function filterRecordsByRootLineBlacklist(array &$records); - /** - * @param array $record - * @return mixed - */ public function prepareRecord(array &$record); - /** - * @param string $columnName - * @return array - */ public function getColumnConfig(string $columnName): array; - /** - * @param integer $offset - * @param integer $limit - * @return array - */ public function getRecords(int $offset, int $limit): array; - /** - * @param integer $identifier - * @return array - */ public function getRecord(int $identifier): array; - /** - * @return string - */ public function getLanguageUidColumn(): string; } diff --git a/Classes/Domain/Model/FacetRequest.php b/Classes/Domain/Model/FacetRequest.php index b79fb9dc..2360877b 100644 --- a/Classes/Domain/Model/FacetRequest.php +++ b/Classes/Domain/Model/FacetRequest.php @@ -38,8 +38,6 @@ class FacetRequest implements FacetRequestInterface /** * As the facets come from configuration this might be a good idea to help * integrators find issues. - * @param string $identifier - * @param array $config */ public function __construct(string $identifier, array $config) { @@ -47,17 +45,11 @@ public function __construct(string $identifier, array $config) $this->config = $config; } - /** - * @return string - */ public function getIdentifier(): string { return $this->identifier; } - /** - * @return array - */ public function getConfig(): array { return $this->config; diff --git a/Classes/Domain/Model/QueryResultInterfaceStub.php b/Classes/Domain/Model/QueryResultInterfaceStub.php index 980ee894..c7af6be7 100644 --- a/Classes/Domain/Model/QueryResultInterfaceStub.php +++ b/Classes/Domain/Model/QueryResultInterfaceStub.php @@ -46,8 +46,6 @@ public function toArray() } /** - * @param $offset - * @return boolean * @throws \BadMethodCallException */ public function offsetExists($offset) @@ -57,7 +55,6 @@ public function offsetExists($offset) } /** - * @param $offset * @throws \BadMethodCallException */ public function offsetGet($offset) @@ -66,8 +63,6 @@ public function offsetGet($offset) } /** - * @param $offset - * @param $value * @throws \BadMethodCallException */ public function offsetSet($offset, $value) @@ -76,7 +71,6 @@ public function offsetSet($offset, $value) } /** - * @param $offset * @throws \BadMethodCallException */ public function offsetUnset($offset) diff --git a/Classes/Domain/Model/ResultItem.php b/Classes/Domain/Model/ResultItem.php index 0230fe65..8f81a6eb 100644 --- a/Classes/Domain/Model/ResultItem.php +++ b/Classes/Domain/Model/ResultItem.php @@ -35,54 +35,33 @@ class ResultItem implements ResultItemInterface */ protected $type = ''; - /** - * ResultItem constructor. - * @param array $result - * @param string $type - */ public function __construct(array $result, string $type) { $this->data = $result; $this->type = $type; } - /** - * @return string - */ public function getType(): string { return $this->type; } - /** - * @return array - */ public function getPlainData(): array { return $this->data; } - /** - * @param mixed $offset - * @return bool - */ public function offsetExists($offset) { return isset($this->data[$offset]); } - /** - * @param mixed $offset - * @return mixed - */ public function offsetGet($offset) { return $this->data[$offset]; } /** - * @param mixed $offset - * @param mixed $value * @throws \BadMethodCallException */ public function offsetSet($offset, $value) @@ -91,7 +70,6 @@ public function offsetSet($offset, $value) } /** - * @param mixed $offset * @throws \BadMethodCallException */ public function offsetUnset($offset) diff --git a/Classes/Domain/Model/SearchRequest.php b/Classes/Domain/Model/SearchRequest.php index 17ef1979..17911f6f 100644 --- a/Classes/Domain/Model/SearchRequest.php +++ b/Classes/Domain/Model/SearchRequest.php @@ -81,42 +81,27 @@ public function __construct(string $query = '') $this->query = $query; } - /** - * @return string - */ public function getQuery(): string { return $this->query; } - /** - * @return string - */ public function getSearchTerm(): string { return $this->query; } - /** - * @param array $filter - */ public function setFilter(array $filter) { $filter = ArrayUtility::removeArrayEntryByValue($filter, ''); $this->filter = CustomArrayUtility::removeEmptyElementsRecursively($filter); } - /** - * @return bool - */ public function hasFilter(): bool { return count($this->filter) > 0; } - /** - * @return array - */ public function getFilter(): array { return $this->filter; @@ -124,8 +109,6 @@ public function getFilter(): array /** * Add a facet to gather in this search request. - * - * @param FacetRequestInterface $facet */ public function addFacet(FacetRequestInterface $facet) { @@ -143,17 +126,12 @@ public function getFacets(): array /** * Define connection to use for this request. * Necessary to allow implementation of execute for interface. - * - * @param ConnectionInterface $connection */ public function setConnection(ConnectionInterface $connection) { $this->connection = $connection; } - /** - * @param SearchService $searchService - */ public function setSearchService(SearchService $searchService) { $this->searchService = $searchService; @@ -163,8 +141,6 @@ public function setSearchService(SearchService $searchService) // Current implementation covers only paginate widget support. /** - * @param bool $returnRawQueryResult - * @return SearchResultInterface * @throws \InvalidArgumentException */ public function execute($returnRawQueryResult = false) @@ -185,10 +161,6 @@ public function execute($returnRawQueryResult = false) return $this->searchService->processResult($this->connection->search($this)); } - /** - * @param integer $limit - * @return $this - */ public function setLimit($limit) { $this->limit = (int)$limit; @@ -196,10 +168,6 @@ public function setLimit($limit) return $this; } - /** - * @param integer $offset - * @return $this - */ public function setOffset($offset) { $this->offset = (int)$offset; @@ -207,17 +175,11 @@ public function setOffset($offset) return $this; } - /** - * @return integer - */ public function getLimit() { return $this->limit; } - /** - * @return integer - */ public function getOffset() { return $this->offset; @@ -232,7 +194,6 @@ public function getSource() } /** - * @param array $orderings * @throws \BadMethodCallException */ public function setOrderings(array $orderings) @@ -241,7 +202,6 @@ public function setOrderings(array $orderings) } /** - * @param \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ConstraintInterface $constraint * @throws \BadMethodCallException */ public function matching($constraint) @@ -250,7 +210,6 @@ public function matching($constraint) } /** - * @param mixed $constraint1 * @throws \BadMethodCallException */ public function logicalAnd($constraint1) @@ -259,7 +218,6 @@ public function logicalAnd($constraint1) } /** - * @param mixed $constraint1 * @throws \BadMethodCallException */ public function logicalOr($constraint1) @@ -268,7 +226,6 @@ public function logicalOr($constraint1) } /** - * @param \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ConstraintInterface $constraint * @throws \BadMethodCallException */ public function logicalNot(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\ConstraintInterface $constraint) @@ -277,9 +234,6 @@ public function logicalNot(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\Constraint } /** - * @param string $propertyName - * @param mixed $operand - * @param bool $caseSensitive * @throws \BadMethodCallException */ public function equals($propertyName, $operand, $caseSensitive = true) @@ -288,9 +242,6 @@ public function equals($propertyName, $operand, $caseSensitive = true) } /** - * @param string $propertyName - * @param string $operand - * @param bool $caseSensitive * @throws \BadMethodCallException */ public function like($propertyName, $operand, $caseSensitive = true) @@ -299,8 +250,6 @@ public function like($propertyName, $operand, $caseSensitive = true) } /** - * @param string $propertyName - * @param mixed $operand * @throws \BadMethodCallException */ public function contains($propertyName, $operand) @@ -309,8 +258,6 @@ public function contains($propertyName, $operand) } /** - * @param string $propertyName - * @param mixed $operand * @throws \BadMethodCallException */ public function in($propertyName, $operand) @@ -319,8 +266,6 @@ public function in($propertyName, $operand) } /** - * @param string $propertyName - * @param mixed $operand * @throws \BadMethodCallException */ public function lessThan($propertyName, $operand) @@ -329,8 +274,6 @@ public function lessThan($propertyName, $operand) } /** - * @param string $propertyName - * @param mixed $operand * @throws \BadMethodCallException */ public function lessThanOrEqual($propertyName, $operand) @@ -339,8 +282,6 @@ public function lessThanOrEqual($propertyName, $operand) } /** - * @param string $propertyName - * @param mixed $operand * @throws \BadMethodCallException */ public function greaterThan($propertyName, $operand) @@ -349,8 +290,6 @@ public function greaterThan($propertyName, $operand) } /** - * @param string $propertyName - * @param mixed $operand * @throws \BadMethodCallException */ public function greaterThanOrEqual($propertyName, $operand) @@ -367,7 +306,6 @@ public function getType() } /** - * @param \TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface $querySettings * @throws \BadMethodCallException */ public function setQuerySettings(\TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface $querySettings) @@ -408,7 +346,6 @@ public function getConstraint() } /** - * @param string $propertyName * @throws \BadMethodCallException */ public function isEmpty($propertyName) @@ -417,7 +354,6 @@ public function isEmpty($propertyName) } /** - * @param \TYPO3\CMS\Extbase\Persistence\Generic\Qom\SourceInterface $source * @throws \BadMethodCallException */ public function setSource(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\SourceInterface $source) diff --git a/Classes/Domain/Model/SearchResult.php b/Classes/Domain/Model/SearchResult.php index 80b88e7a..e3697cb2 100644 --- a/Classes/Domain/Model/SearchResult.php +++ b/Classes/Domain/Model/SearchResult.php @@ -53,11 +53,6 @@ class SearchResult implements SearchResultInterface */ protected $position = 0; - /** - * SearchResult constructor. - * @param SearchResultInterface $originalSearchResult - * @param array $resultItems - */ public function __construct(SearchResultInterface $originalSearchResult, array $resultItems) { $this->originalSearchResult = $originalSearchResult; @@ -74,9 +69,6 @@ public function getResults(): array return $this->results; } - /** - * @return void - */ protected function initResults() { if (is_array($this->results)) { @@ -89,41 +81,26 @@ protected function initResults() } } - /** - * @return array - */ public function getFacets(): array { return $this->originalSearchResult->getFacets(); } - /** - * @return integer - */ public function getCurrentCount(): int { return $this->originalSearchResult->getCurrentCount(); } - /** - * @return integer - */ public function count() { return $this->originalSearchResult->count(); } - /** - * @return mixed - */ public function current() { return $this->getResults()[$this->position]; } - /** - * @return mixed - */ public function next() { ++$this->position; @@ -131,33 +108,21 @@ public function next() return $this->current(); } - /** - * @return integer|mixed - */ public function key() { return $this->position; } - /** - * @return bool - */ public function valid() { return isset($this->getResults()[$this->position]); } - /** - * @return void - */ public function rewind() { $this->position = 0; } - /** - * @return \TYPO3\CMS\Extbase\Persistence\QueryInterface - */ public function getQuery() { return $this->originalSearchResult->getQuery(); diff --git a/Classes/Domain/Search/CachedSearchService.php b/Classes/Domain/Search/CachedSearchService.php index 0976521e..48a16140 100644 --- a/Classes/Domain/Search/CachedSearchService.php +++ b/Classes/Domain/Search/CachedSearchService.php @@ -41,18 +41,11 @@ class CachedSearchService implements SingletonInterface */ protected $searchService; - /** - * @param SearchService $searchService - */ public function __construct(SearchService $searchService) { $this->searchService = $searchService; } - /** - * @param SearchRequestInterface $searchRequest - * @return SearchResultInterface - */ public function search(SearchRequestInterface $searchRequest): SearchResultInterface { $hash = $this->getHash($searchRequest); @@ -62,10 +55,6 @@ public function search(SearchRequestInterface $searchRequest): SearchResultInter return $this->results[$hash] = $this->searchService->search($searchRequest); } - /** - * @param SearchRequestInterface $searchRequest - * @return string - */ protected function getHash(SearchRequestInterface $searchRequest): string { if (is_callable([$searchRequest, 'getRequestHash'])) { diff --git a/Classes/Domain/Search/QueryFactory.php b/Classes/Domain/Search/QueryFactory.php index f397a21a..66eaf16b 100644 --- a/Classes/Domain/Search/QueryFactory.php +++ b/Classes/Domain/Search/QueryFactory.php @@ -45,12 +45,6 @@ class QueryFactory */ protected $configurationUtility; - /** - * QueryFactory constructor. - * @param \TYPO3\CMS\Core\Log\LogManager $logManager - * @param ConfigurationContainerInterface $configuration - * @param ConfigurationUtility $configurationUtility - */ public function __construct( \TYPO3\CMS\Core\Log\LogManager $logManager, ConfigurationContainerInterface $configuration, @@ -65,19 +59,12 @@ public function __construct( * TODO: This is not in scope Elasticsearch, therefore it should not return * \Elastica\Query, but decide to use a more specific QueryFactory like * ElasticaQueryFactory, once the second query is added? - * - * @param SearchRequestInterface $searchRequest - * @return \Elastica\Query */ public function create(SearchRequestInterface $searchRequest): \Elastica\Query { return $this->createElasticaQuery($searchRequest); } - /** - * @param SearchRequestInterface $searchRequest - * @return \Elastica\Query - */ protected function createElasticaQuery(SearchRequestInterface $searchRequest): \Elastica\Query { $query = []; @@ -97,10 +84,6 @@ protected function createElasticaQuery(SearchRequestInterface $searchRequest): \ return new \Elastica\Query($query); } - /** - * @param SearchRequestInterface $searchRequest - * @param array $query - */ protected function addSize(SearchRequestInterface $searchRequest, array &$query) { ArrayUtility::mergeRecursiveWithOverrule($query, [ @@ -109,10 +92,6 @@ protected function addSize(SearchRequestInterface $searchRequest, array &$query) ]); } - /** - * @param SearchRequestInterface $searchRequest - * @param array $query - */ protected function addSearch(SearchRequestInterface $searchRequest, array &$query) { if (trim($searchRequest->getSearchTerm()) === '') { @@ -145,10 +124,6 @@ protected function addSearch(SearchRequestInterface $searchRequest, array &$quer $query = ArrayUtility::setValueByPath($query, 'query.bool.must.0.multi_match', $matchExpression, '.'); } - /** - * @param SearchRequestInterface $searchRequest - * @param array $query - */ protected function addBoosts(SearchRequestInterface $searchRequest, array &$query) { try { @@ -185,10 +160,6 @@ protected function addBoosts(SearchRequestInterface $searchRequest, array &$quer } } - /** - * @param array $query - * @return void - */ protected function addFactorBoost(array &$query) { try { @@ -203,11 +174,6 @@ protected function addFactorBoost(array &$query) } } - /** - * @param SearchRequestInterface $searchRequest - * @param array $query - * @return void - */ protected function addFields(SearchRequestInterface $searchRequest, array &$query) { try { @@ -237,11 +203,6 @@ protected function addFields(SearchRequestInterface $searchRequest, array &$quer } } - /** - * @param SearchRequestInterface $searchRequest - * @param array $query - * @return void - */ protected function addSort(SearchRequestInterface $searchRequest, array &$query) { $sorting = $this->configuration->getIfExists('searching.sort') ?: []; @@ -252,11 +213,6 @@ protected function addSort(SearchRequestInterface $searchRequest, array &$query) } } - /** - * @param SearchRequestInterface $searchRequest - * @param array $query - * @return void - */ protected function addFilters(SearchRequestInterface $searchRequest, array &$query) { if (!$searchRequest->hasFilter()) { @@ -273,13 +229,6 @@ protected function addFilters(SearchRequestInterface $searchRequest, array &$que } } - /** - * @param string $name - * @param string $value - * @param array $config - * @param array $query - * @return array - */ protected function addFilter(string $name, $value, array $config, array &$query): array { if (!empty($config)) { @@ -329,11 +278,6 @@ protected function addFilter(string $name, $value, array $config, array &$query) return $query; } - /** - * @param SearchRequestInterface $searchRequest - * @param array $query - * @return void - */ protected function addFacets(SearchRequestInterface $searchRequest, array &$query) { foreach ($searchRequest->getFacets() as $facet) { diff --git a/Classes/Domain/Search/SearchService.php b/Classes/Domain/Search/SearchService.php index 6bb99fb9..01c6f1b6 100644 --- a/Classes/Domain/Search/SearchService.php +++ b/Classes/Domain/Search/SearchService.php @@ -75,10 +75,6 @@ public function __construct( $this->dataProcessorService = $dataProcessorService; } - /** - * @param SearchRequestInterface $searchRequest - * @return SearchResultInterface - */ public function search(SearchRequestInterface $searchRequest): SearchResultInterface { $this->addSize($searchRequest); @@ -94,8 +90,6 @@ public function search(SearchRequestInterface $searchRequest): SearchResultInter /** * Add configured size of search result items to request. - * - * @param SearchRequestInterface $searchRequest */ protected function addSize(SearchRequestInterface $searchRequest) { @@ -106,8 +100,6 @@ protected function addSize(SearchRequestInterface $searchRequest) /** * Add facets from configuration to request. - * - * @param SearchRequestInterface $searchRequest */ protected function addConfiguredFacets(SearchRequestInterface $searchRequest) { @@ -127,8 +119,6 @@ protected function addConfiguredFacets(SearchRequestInterface $searchRequest) /** * Add filters from configuration, e.g. flexform or TypoScript. - * - * @param SearchRequestInterface $searchRequest */ protected function addConfiguredFilters(SearchRequestInterface $searchRequest) { @@ -148,9 +138,6 @@ protected function addConfiguredFilters(SearchRequestInterface $searchRequest) /** * Processes the result, e.g. applies configured data processing to result. - * - * @param SearchResultInterface $searchResult - * @return SearchResultInterface */ public function processResult(SearchResultInterface $searchResult): SearchResultInterface { diff --git a/Classes/Domain/Service/DataHandler.php b/Classes/Domain/Service/DataHandler.php index 1e2076f6..f085a365 100644 --- a/Classes/Domain/Service/DataHandler.php +++ b/Classes/Domain/Service/DataHandler.php @@ -73,11 +73,6 @@ public function injectLogger(\TYPO3\CMS\Core\Log\LogManager $logManager) $this->logger = $logManager->getLogger(__CLASS__); } - /** - * DataHandler constructor. - * @param ConfigurationContainerInterface $configuration - * @param IndexerFactory $indexerFactory - */ public function __construct(ConfigurationContainerInterface $configuration, IndexerFactory $indexerFactory) { $this->configuration = $configuration; @@ -85,9 +80,6 @@ public function __construct(ConfigurationContainerInterface $configuration, Inde } /** - * @param string $table - * @param array $record - * @return void * @throws NoMatchingIndexerException */ public function update(string $table, array $record) @@ -96,11 +88,6 @@ public function update(string $table, array $record) $this->getIndexer($table)->indexDocument($record['uid']); } - /** - * @param string $table - * @param string $identifier - * @return void - */ public function delete(string $table, string $identifier) { $this->logger->debug('Record received for delete.', [$table, $identifier]); @@ -108,8 +95,6 @@ public function delete(string $table, string $identifier) } /** - * @param string $table - * @return IndexerInterface * @throws NoMatchingIndexerException */ protected function getIndexer(string $table): IndexerInterface @@ -117,10 +102,6 @@ protected function getIndexer(string $table): IndexerInterface return $this->indexerFactory->getIndexer($table); } - /** - * @param string $table - * @return boolean - */ public function supportsTable(string $table): bool { try { diff --git a/Classes/Hook/DataHandler.php b/Classes/Hook/DataHandler.php index 8f6b8c92..74584ae4 100644 --- a/Classes/Hook/DataHandler.php +++ b/Classes/Hook/DataHandler.php @@ -50,8 +50,6 @@ class DataHandler implements Singleton /** * Dependency injection as TYPO3 doesn't provide it on it's own. * Still you can submit your own dataHandler. - * @param OwnDataHandler $dataHandler - * @param Logger $logger */ public function __construct(OwnDataHandler $dataHandler = null, Logger $logger = null) { @@ -75,10 +73,6 @@ public function __construct(OwnDataHandler $dataHandler = null, Logger $logger = /** * Called by CoreDataHandler on deletion of records. - * - * @param string $table - * @param string $uid - * @return bool */ public function processCmdmap_deleteAction(string $table, string $uid): bool { @@ -92,8 +86,6 @@ public function processCmdmap_deleteAction(string $table, string $uid): bool } /** - * @param CoreDataHandler $dataHandler - * @return void * @throws NoMatchingIndexerException */ public function processDatamap_afterAllOperations(CoreDataHandler $dataHandler) @@ -117,9 +109,6 @@ public function processDatamap_afterAllOperations(CoreDataHandler $dataHandler) } /** - * @param array $parameters - * @param CoreDataHandler $dataHandler - * @return void * @throws NoMatchingIndexerException */ public function clearCachePostProc(array $parameters, CoreDataHandler $dataHandler) @@ -141,9 +130,6 @@ public function clearCachePostProc(array $parameters, CoreDataHandler $dataHandl } /** - * @param string $table - * @param integer $uid - * @return bool * @throws NoMatchingIndexerException */ protected function processRecord(string $table, int $uid): bool @@ -163,10 +149,6 @@ protected function processRecord(string $table, int $uid): bool return false; } - /** - * @param string $table - * @return bool - */ protected function shouldProcessHookForTable(string $table): bool { if ($this->dataHandler === null) { @@ -184,8 +166,6 @@ protected function shouldProcessHookForTable(string $table): bool /** * Wrapper to allow unit testing. * - * @param string $table - * @param integer $uid * @return array|null */ protected function getRecord(string $table, int $uid) diff --git a/Classes/Hook/Filter/FrontendUserAccessFilter.php b/Classes/Hook/Filter/FrontendUserAccessFilter.php index fc19fecc..e96276f4 100644 --- a/Classes/Hook/Filter/FrontendUserAccessFilter.php +++ b/Classes/Hook/Filter/FrontendUserAccessFilter.php @@ -38,10 +38,6 @@ public function generate($parameters) $this->appendQueryWithAccessFilter($parameters['query'], $parameters['value']); } - /** - * @param array $query - * @param string $field - */ protected function appendQueryWithAccessFilter(array &$query, string $field) { $query['query']['bool']['must'][] = [ @@ -49,9 +45,6 @@ protected function appendQueryWithAccessFilter(array &$query, string $field) ]; } - /** - * @return array - */ protected function getUserGroups(): array { $feUser = $this->getFrontendUserAuthentication(); @@ -72,10 +65,7 @@ protected function getUserGroups(): array return [0]; } - /** - * @return FrontendUserAuthentication - */ - protected function getFrontendUserAuthentication() + protected function getFrontendUserAuthentication(): FrontendUserAuthentication { return $GLOBALS['TSFE']->fe_user ?? null; } diff --git a/Classes/Integration/Form/Finisher/DataHandlerFinisher.php b/Classes/Integration/Form/Finisher/DataHandlerFinisher.php index c98660f2..1751cd6a 100644 --- a/Classes/Integration/Form/Finisher/DataHandlerFinisher.php +++ b/Classes/Integration/Form/Finisher/DataHandlerFinisher.php @@ -49,7 +49,6 @@ class DataHandlerFinisher extends AbstractFinisher ]; /** - * @return void * @throws FinisherException * @throws NoMatchingIndexerException */ diff --git a/Classes/Utility/ArrayUtility.php b/Classes/Utility/ArrayUtility.php index aff18b3e..e77c056d 100644 --- a/Classes/Utility/ArrayUtility.php +++ b/Classes/Utility/ArrayUtility.php @@ -8,12 +8,9 @@ */ class ArrayUtility { - /** * Recursively removes empty array elements. * - * @param array $array - * @return array the modified array * @see \TYPO3\CMS\Extbase\Utility\ArrayUtility::removeEmptyElementsRecursively Removed in TYPO3 v9 */ public static function removeEmptyElementsRecursively(array $array): array diff --git a/Classes/Utility/FrontendUtility.php b/Classes/Utility/FrontendUtility.php index 446bf364..383ae74a 100644 --- a/Classes/Utility/FrontendUtility.php +++ b/Classes/Utility/FrontendUtility.php @@ -30,9 +30,6 @@ */ class FrontendUtility extends BackendUtility { - /** - * @return TypoScriptFrontendController - */ protected static function getLanguageService(): TypoScriptFrontendController { return $GLOBALS['TSFE']; From ab1b6b5da9c67d6c028790ee25286d053fbf9713 Mon Sep 17 00:00:00 2001 From: Benjamin Serfhos Date: Mon, 29 Oct 2018 09:52:18 +0100 Subject: [PATCH 32/73] [TASK] Finetune so interface is not reliant for Elastica library --- Classes/Connection/ConnectionInterface.php | 10 ++++------ Classes/Connection/Elasticsearch.php | 12 ++++++++++++ Classes/Domain/Index/AbstractIndexer.php | 9 +-------- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/Classes/Connection/ConnectionInterface.php b/Classes/Connection/ConnectionInterface.php index 9480d041..76122f8b 100644 --- a/Classes/Connection/ConnectionInterface.php +++ b/Classes/Connection/ConnectionInterface.php @@ -21,8 +21,6 @@ * 02110-1301, USA. */ -use Elastica\Query; - /** * Defines interface for connections to storage backend for interacting with documents. */ @@ -58,12 +56,12 @@ public function deleteDocument(string $documentType, string $identifier); public function search(SearchRequestInterface $searchRequest): SearchResultInterface; /** - * Will delete the whole index / db. + * Will delete the index / db of defined document type. */ - public function deleteIndex(); + public function deleteIndexByDocumentType(string $documentType); /** - * Will delete the index / db of defined document type. + * Will delete the whole index / db. */ - public function deleteIndexByQuery(Query $query); + public function deleteIndex(); } diff --git a/Classes/Connection/Elasticsearch.php b/Classes/Connection/Elasticsearch.php index b77253b5..c7e85041 100644 --- a/Classes/Connection/Elasticsearch.php +++ b/Classes/Connection/Elasticsearch.php @@ -176,6 +176,18 @@ public function deleteIndex() $index->delete(); } + public function deleteIndexByDocumentType(string $documentType) + { + $query = Query::create([ + 'query' => [ + 'term' => [ + 'search_document_type' => $documentType + ] + ] + ]); + $this->deleteIndexByQuery($query); + } + public function deleteIndexByQuery(Query $query) { $index = $this->connection->getClient()->getIndex($this->indexFactory->getIndexName()); diff --git a/Classes/Domain/Index/AbstractIndexer.php b/Classes/Domain/Index/AbstractIndexer.php index a016de02..797bbb2f 100644 --- a/Classes/Domain/Index/AbstractIndexer.php +++ b/Classes/Domain/Index/AbstractIndexer.php @@ -24,7 +24,6 @@ use Codappix\SearchCore\Configuration\ConfigurationContainerInterface; use Codappix\SearchCore\Configuration\InvalidArgumentException; use Codappix\SearchCore\Connection\ConnectionInterface; -use Elastica\Query; use TYPO3\CMS\Core\Utility\GeneralUtility; abstract class AbstractIndexer implements IndexerInterface @@ -114,13 +113,7 @@ public function delete() public function deleteDocuments() { $this->logger->info('Start deletion of indexed documents.'); - $this->connection->deleteIndexByQuery(Query::create([ - 'query' => [ - 'term' => [ - 'search_document_type' => $this->getDocumentName() - ] - ] - ])); + $this->connection->deleteIndexByDocumentType($this->getDocumentName()); $this->logger->info('Finish deletion.'); } From 4000699812881cdcc00fea477f8c85a7a44a17cd Mon Sep 17 00:00:00 2001 From: Benjamin Serfhos Date: Mon, 29 Oct 2018 09:54:48 +0100 Subject: [PATCH 33/73] [TASK] Remove duplicate search_identifier in index --- Classes/Connection/Elasticsearch/DocumentFactory.php | 1 + 1 file changed, 1 insertion(+) diff --git a/Classes/Connection/Elasticsearch/DocumentFactory.php b/Classes/Connection/Elasticsearch/DocumentFactory.php index ca90ebed..d5707892 100644 --- a/Classes/Connection/Elasticsearch/DocumentFactory.php +++ b/Classes/Connection/Elasticsearch/DocumentFactory.php @@ -57,6 +57,7 @@ public function getDocument(string $documentType, array $document): \Elastica\Do } $identifier = $document['search_identifier']; + unset($document['search_identifier']); $this->logger->debug( sprintf('Convert %s %u to document.', $documentType, $identifier), From f1eb85de6459998d8ce4f5574865a0d910550192 Mon Sep 17 00:00:00 2001 From: Benjamin Serfhos Date: Mon, 29 Oct 2018 10:01:05 +0100 Subject: [PATCH 34/73] [TASK] Remove double variables --- Classes/Domain/Index/TcaIndexer/RelationResolver.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Classes/Domain/Index/TcaIndexer/RelationResolver.php b/Classes/Domain/Index/TcaIndexer/RelationResolver.php index 6796d13c..3a33796d 100644 --- a/Classes/Domain/Index/TcaIndexer/RelationResolver.php +++ b/Classes/Domain/Index/TcaIndexer/RelationResolver.php @@ -104,7 +104,7 @@ protected function getUtilityForMode(): string protected function getColumnValue(array $record, string $column, TcaTableServiceInterface $service): string { $utility = GeneralUtility::makeInstance($this->getUtilityForMode()); - $value = $value = $utility::getProcessedValueExtra( + $value = $utility::getProcessedValueExtra( $service->getTableName(), $column, $record[$column], From 9b0b0305a7a8b957efb656bc79c4c93fc57e0068 Mon Sep 17 00:00:00 2001 From: Benjamin Serfhos Date: Mon, 29 Oct 2018 13:49:38 +0100 Subject: [PATCH 35/73] [BUGFIX] Make sure the while loop is not closed When filterRecordsByRootLineBlacklist() returns no results, loop should just ask the next items based on iteration --- Classes/Domain/Index/AbstractIndexer.php | 11 ++++++++--- Classes/Domain/Index/TcaIndexer.php | 7 +++++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/Classes/Domain/Index/AbstractIndexer.php b/Classes/Domain/Index/AbstractIndexer.php index 797bbb2f..adb172e4 100644 --- a/Classes/Domain/Index/AbstractIndexer.php +++ b/Classes/Domain/Index/AbstractIndexer.php @@ -122,8 +122,10 @@ protected function getRecordGenerator(): \Generator $offset = 0; $limit = $this->getLimit(); - while (($records = $this->getRecords($offset, $limit)) !== []) { - yield $records; + while (($records = $this->getRecords($offset, $limit)) !== null) { + if (!empty($records)) { + yield $records; + } $offset += $limit; } } @@ -194,7 +196,10 @@ public function getIdentifier(): string return $this->identifier; } - abstract protected function getRecords(int $offset, int $limit): array; + /** + * @return array|null Nullable when no items are found and execution should be stopped + */ + abstract protected function getRecords(int $offset, int $limit); /** * @throws NoRecordFoundException If record could not be found. diff --git a/Classes/Domain/Index/TcaIndexer.php b/Classes/Domain/Index/TcaIndexer.php index 39170efb..e1b03b75 100644 --- a/Classes/Domain/Index/TcaIndexer.php +++ b/Classes/Domain/Index/TcaIndexer.php @@ -49,11 +49,14 @@ public function __construct( $this->tcaTableService = $tcaTableService; } - protected function getRecords(int $offset, int $limit): array + /** + * @return array|null Nullable when no items are found and execution should be stopped + */ + protected function getRecords(int $offset, int $limit) { $records = $this->tcaTableService->getRecords($offset, $limit); if ($records === []) { - return []; + return null; } $this->tcaTableService->filterRecordsByRootLineBlacklist($records); From 5250f97809b55b8c11259561ce6df9a6f1932253 Mon Sep 17 00:00:00 2001 From: Benjamin Serfhos Date: Mon, 29 Oct 2018 14:01:03 +0100 Subject: [PATCH 36/73] [BUGFIX] Make sure boolean is returned for strict return type When configured by comma seperate list, it should return true --- Classes/Domain/Index/TcaIndexer/TcaTableService.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Classes/Domain/Index/TcaIndexer/TcaTableService.php b/Classes/Domain/Index/TcaIndexer/TcaTableService.php index 6216dae6..5e405891 100644 --- a/Classes/Domain/Index/TcaIndexer/TcaTableService.php +++ b/Classes/Domain/Index/TcaIndexer/TcaTableService.php @@ -384,7 +384,7 @@ protected function isRecordBlacklistedByRootline(array &$record): bool */ protected function isBlackListedRootLineConfigured(): bool { - return $this->configuration->getIfExists('indexing.' . $this->getTableName() . '.rootLineBlacklist'); + return (bool)$this->configuration->getIfExists('indexing.' . $this->getTableName() . '.rootLineBlacklist'); } /** @@ -396,7 +396,8 @@ protected function getBlackListedRootLine(): array { return GeneralUtility::intExplode( ',', - $this->configuration->getIfExists('indexing.' . $this->getTableName() . '.rootLineBlacklist') + $this->configuration->getIfExists('indexing.' . $this->getTableName() . '.rootLineBlacklist'), + true ); } From 4b7337d3fab9019a79b33d6e6e7bfbb975144718 Mon Sep 17 00:00:00 2001 From: Benjamin Serfhos Date: Mon, 29 Oct 2018 14:01:53 +0100 Subject: [PATCH 37/73] [TASK] Use generic namespace for fluid --- Resources/Private/Layouts/Default.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/Private/Layouts/Default.html b/Resources/Private/Layouts/Default.html index c12a1372..4866c205 100644 --- a/Resources/Private/Layouts/Default.html +++ b/Resources/Private/Layouts/Default.html @@ -1,4 +1,4 @@ -
From 209f441b5da92236a9a4c8651ab9003472a0ca1d Mon Sep 17 00:00:00 2001 From: Benjamin Serfhos Date: Mon, 29 Oct 2018 14:13:34 +0100 Subject: [PATCH 38/73] [TASK] Added link generation based on fluid templates Removed search_page_typolink parameter from index --- .../Index/TcaIndexer/TcaTableService.php | 17 ------------- .../20181028-fluid-templating-list-items.rst | 24 +++++++++++++++++++ .../Partials/Results/Item/Default.html | 8 +++++++ .../Private/Partials/Results/ListItem.html | 4 +--- 4 files changed, 33 insertions(+), 20 deletions(-) create mode 100644 Documentation/source/changelog/20181028-fluid-templating-list-items.rst create mode 100644 Resources/Private/Partials/Results/Item/Default.html diff --git a/Classes/Domain/Index/TcaIndexer/TcaTableService.php b/Classes/Domain/Index/TcaIndexer/TcaTableService.php index 5e405891..ab5c70c9 100644 --- a/Classes/Domain/Index/TcaIndexer/TcaTableService.php +++ b/Classes/Domain/Index/TcaIndexer/TcaTableService.php @@ -159,23 +159,6 @@ public function prepareRecord(array &$record) // Always fallback on public visibility when configured $record['search_access'] = !empty($groups) ? $groups : [0]; } - - if (!isset($record['search_page_typolink'])) { - switch ($this->tableName) { - case 'pages': - $record['search_page_typolink'] = 't3://page?uid=' . $record['uid']; - break; - case 'tt_content': - $record['search_page_typolink'] = 't3://page?uid=' . $record['pid'] . '#' . $record['uid']; - break; - case 'sys_file': - $record['search_page_typolink'] = 't3://file?uid=' . $record['uid']; - break; - default: - $record['search_page_typolink'] = 't3://page?uid=' . $record['pid']; - break; - } - } } protected function getWhereClause(): Where diff --git a/Documentation/source/changelog/20181028-fluid-templating-list-items.rst b/Documentation/source/changelog/20181028-fluid-templating-list-items.rst new file mode 100644 index 00000000..05501805 --- /dev/null +++ b/Documentation/source/changelog/20181028-fluid-templating-list-items.rst @@ -0,0 +1,24 @@ +Feature "Added fluid partials for list items" +============================================= + +When using a seperate partial for ListItem you can simply adjust for your custom page type: + +Example ListItem.html:: +----------------------- +.. code-block:: html + :linenos: + + + + + Add opening for possible different partials based on Document types: + + + + {f:render(partial: 'Results/Item/YourDocumentType', arguments: {result: result})} + {f:render(partial: 'Results/Item/Page', arguments: {result: result})} + {f:render(partial: 'Results/Item/Unknown', arguments: {result: result})} + + + diff --git a/Resources/Private/Partials/Results/Item/Default.html b/Resources/Private/Partials/Results/Item/Default.html new file mode 100644 index 00000000..a4b5fdc3 --- /dev/null +++ b/Resources/Private/Partials/Results/Item/Default.html @@ -0,0 +1,8 @@ + + + + [{result.search_document_type}:{result.uid}] - {result.search_title} + + + diff --git a/Resources/Private/Partials/Results/ListItem.html b/Resources/Private/Partials/Results/ListItem.html index 1ef408b5..34e5f8b9 100644 --- a/Resources/Private/Partials/Results/ListItem.html +++ b/Resources/Private/Partials/Results/ListItem.html @@ -1,8 +1,6 @@ - - [{result.search_document_type}:{result.uid}] - {result.search_title} - + From 2c5ab1b57afcec138b3d2e8b90198ec0c1adeea3 Mon Sep 17 00:00:00 2001 From: Benjamin Serfhos Date: Mon, 29 Oct 2018 14:19:23 +0100 Subject: [PATCH 39/73] [TASK] Add documentation for frontend user access feature --- .../changelog/20181028-user-access-indexed.rst | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 Documentation/source/changelog/20181028-user-access-indexed.rst diff --git a/Documentation/source/changelog/20181028-user-access-indexed.rst b/Documentation/source/changelog/20181028-user-access-indexed.rst new file mode 100644 index 00000000..966dacb0 --- /dev/null +++ b/Documentation/source/changelog/20181028-user-access-indexed.rst @@ -0,0 +1,14 @@ +Feature "Added frontend user authentication access" +=============================================================== + +Indexation added based on page access via ``fe_group`` and inherited +from ```extendToSubpages```. + +The searching is added via typoscript using the UserFunc filter:: + + frontendUserAccess { + type = user + userFunc = Codappix\SearchCore\Hook\Filter\FrontendUserAccessFilter->generate + } + +To bypass this filter simply unset default filter in searching.filter From 2ee4a88a6705214a801670a75ee869801f8e61dc Mon Sep 17 00:00:00 2001 From: Benjamin Serfhos Date: Mon, 29 Oct 2018 14:29:31 +0100 Subject: [PATCH 40/73] [TASK] Add objectmanager via constructor DI injection --- .../Domain/Index/TcaIndexer/PagesIndexer.php | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/Classes/Domain/Index/TcaIndexer/PagesIndexer.php b/Classes/Domain/Index/TcaIndexer/PagesIndexer.php index d77465fe..1718cb85 100644 --- a/Classes/Domain/Index/TcaIndexer/PagesIndexer.php +++ b/Classes/Domain/Index/TcaIndexer/PagesIndexer.php @@ -27,12 +27,18 @@ use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Core\Utility\RootlineUtility; use TYPO3\CMS\Extbase\Object\ObjectManager; +use TYPO3\CMS\Extbase\Object\ObjectManagerInterface; /** * Specific indexer for Pages, will basically add content of page. */ class PagesIndexer extends TcaIndexer { + /** + * @var ObjectManagerInterface + */ + protected $objectManager; + /** * @var TcaTableServiceInterface */ @@ -44,20 +50,16 @@ class PagesIndexer extends TcaIndexer */ protected $fileRepository; - /** - * @param TcaTableServiceInterface $tcaTableService - * @param TcaTableServiceInterface $contentTableService - * @param ConnectionInterface $connection - * @param ConfigurationContainerInterface $configuration - */ public function __construct( TcaTableServiceInterface $tcaTableService, TcaTableServiceInterface $contentTableService, ConnectionInterface $connection, - ConfigurationContainerInterface $configuration + ConfigurationContainerInterface $configuration, + ObjectManagerInterface $objectManager ) { parent::__construct($tcaTableService, $connection, $configuration); $this->contentTableService = $contentTableService; + $this->objectManager = $objectManager; } protected function prepareRecord(array &$record) @@ -141,8 +143,7 @@ protected function fetchMediaForPage(int $uid): array protected function fetchAccess(int $uid, array $pageAccess): array { try { - $objectManager = GeneralUtility::makeInstance(ObjectManager::class); - $rootline = $objectManager->get(RootlineUtility::class, $uid)->get(); + $rootline = $this->objectManager->get(RootlineUtility::class, $uid)->get(); } catch (\RuntimeException $e) { $this->logger->notice( sprintf('Could not fetch rootline for page %u, because: %s', $uid, $e->getMessage()), From b8d708874e06fd516b6c4300fce9855c813626c1 Mon Sep 17 00:00:00 2001 From: Benjamin Serfhos Date: Mon, 29 Oct 2018 15:11:25 +0100 Subject: [PATCH 41/73] [TASK] Revert to only one plugin based on feedback --- .../Configuration/ConfigurationContainer.php | 2 +- Configuration/TCA/Overrides/tt_content.php | 25 ++++++------------- .../Mod/Wizards/NewContentElement.tsconfig | 20 ++++----------- Resources/Private/Language/locallang_be.xlf | 12 +++------ Resources/Private/Templates/Search/Form.html | 11 -------- .../Private/Templates/Search/Results.html | 4 +++ .../{PluginResults.svg => PluginSearch.svg} | 0 ext_localconf.php | 24 ++++++------------ 8 files changed, 29 insertions(+), 69 deletions(-) delete mode 100644 Resources/Private/Templates/Search/Form.html rename Resources/Public/Icons/{PluginResults.svg => PluginSearch.svg} (100%) diff --git a/Classes/Configuration/ConfigurationContainer.php b/Classes/Configuration/ConfigurationContainer.php index 476c94e5..e454a249 100644 --- a/Classes/Configuration/ConfigurationContainer.php +++ b/Classes/Configuration/ConfigurationContainer.php @@ -45,7 +45,7 @@ public function injectConfigurationManager(ConfigurationManagerInterface $config $this->settings = $configurationManager->getConfiguration( ConfigurationManagerInterface::CONFIGURATION_TYPE_SETTINGS, 'SearchCore', - 'Results' + 'Search' ); if ($this->settings === null) { throw new NoConfigurationException('Could not fetch configuration.', 1484226842); diff --git a/Configuration/TCA/Overrides/tt_content.php b/Configuration/TCA/Overrides/tt_content.php index 59ad7ede..5bb389a8 100644 --- a/Configuration/TCA/Overrides/tt_content.php +++ b/Configuration/TCA/Overrides/tt_content.php @@ -3,21 +3,12 @@ use TYPO3\CMS\Extbase\Utility\ExtensionUtility; call_user_func(function ($extension, $table) { - $plugin = ExtensionUtility::registerPlugin( - 'Codappix.' . $extension, - 'Results', - 'LLL:EXT:search_core/Resources/Private/Language/locallang_be.xlf:plugin.results.title', - 'EXT:search_core/Resources/Public/Icons/PluginResults.svg' - ) ?? 'searchcore_results'; - - $GLOBALS['TCA'][$table]['types']['list']['subtypes_excludelist'][$plugin] = 'recursive,pages'; - - $plugin = ExtensionUtility::registerPlugin( - 'Codappix.' . $extension, - 'Form', - 'LLL:EXT:search_core/Resources/Private/Language/locallang_be.xlf:plugin.form.title', - 'EXT:search_core/Resources/Public/Icons/PluginForm.svg' - ) ?? 'searchcore_form'; - - $GLOBALS['TCA'][$table]['types']['list']['subtypes_excludelist'][$plugin] = 'recursive,pages'; + ExtensionUtility::registerPlugin( + 'Codappix.' . $extension, + 'Search', + 'LLL:EXT:search_core/Resources/Private/Language/locallang_be.xlf:plugin.search.title', + 'plugin-' . $extension . '-search' + ); + + $GLOBALS['TCA'][$table]['types']['list']['subtypes_excludelist']['searchcore_search'] = 'recursive,pages'; }, 'search_core', 'tt_content'); diff --git a/Configuration/TSconfig/Page/Mod/Wizards/NewContentElement.tsconfig b/Configuration/TSconfig/Page/Mod/Wizards/NewContentElement.tsconfig index e65d17b4..d2d69384 100644 --- a/Configuration/TSconfig/Page/Mod/Wizards/NewContentElement.tsconfig +++ b/Configuration/TSconfig/Page/Mod/Wizards/NewContentElement.tsconfig @@ -1,22 +1,12 @@ mod.wizards.newContentElement.wizardItems.plugins { elements { - searchcore_results { - title = LLL:EXT:search_core/Resources/Private/Language/locallang_be.xlf:plugin.results.title - description = LLL:EXT:search_core/Resources/Private/Language/locallang_be.xlf:plugin.results.description - iconIdentifier = plugin-search_core-results + searchcore_search { + title = LLL:EXT:search_core/Resources/Private/Language/locallang_be.xlf:plugin.search.title + description = LLL:EXT:search_core/Resources/Private/Language/locallang_be.xlf:plugin.search.description + iconIdentifier = plugin-search_core-search tt_content_defValues { CType = list - list_type = searchcore_results - } - } - - searchcore_form { - title = LLL:EXT:search_core/Resources/Private/Language/locallang_be.xlf:plugin.form.title - description = LLL:EXT:search_core/Resources/Private/Language/locallang_be.xlf:plugin.form.description - iconIdentifier = plugin-search_core-form - tt_content_defValues { - CType = list - list_type = searchcore_form + list_type = searchcore_search } } } diff --git a/Resources/Private/Language/locallang_be.xlf b/Resources/Private/Language/locallang_be.xlf index 28a7bb88..524d5e09 100644 --- a/Resources/Private/Language/locallang_be.xlf +++ b/Resources/Private/Language/locallang_be.xlf @@ -3,18 +3,12 @@
- - Search Core: Results + + Search Core: Search - + List results from search - - Search Core: Form - - - Just a search form to list page - diff --git a/Resources/Private/Templates/Search/Form.html b/Resources/Private/Templates/Search/Form.html deleted file mode 100644 index a7002c44..00000000 --- a/Resources/Private/Templates/Search/Form.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - -
- -
-
- - diff --git a/Resources/Private/Templates/Search/Results.html b/Resources/Private/Templates/Search/Results.html index f2efc3d6..095d2751 100644 --- a/Resources/Private/Templates/Search/Results.html +++ b/Resources/Private/Templates/Search/Results.html @@ -3,6 +3,10 @@ +
+ +
+
    diff --git a/Resources/Public/Icons/PluginResults.svg b/Resources/Public/Icons/PluginSearch.svg similarity index 100% rename from Resources/Public/Icons/PluginResults.svg rename to Resources/Public/Icons/PluginSearch.svg diff --git a/ext_localconf.php b/ext_localconf.php index afc2a451..8452ac8a 100644 --- a/ext_localconf.php +++ b/ext_localconf.php @@ -12,9 +12,9 @@ ['source' => 'EXT:search_core/Resources/Public/Icons/PluginForm.svg'] ); $iconRegistry->registerIcon( - 'plugin-' . $extension . '-results', + 'plugin-' . $extension . '-search', \TYPO3\CMS\Core\Imaging\IconProvider\SvgIconProvider::class, - ['source' => 'EXT:search_core/Resources/Public/Icons/PluginResults.svg'] + ['source' => 'EXT:search_core/Resources/Public/Icons/PluginSearch.svg'] ); // TODO: Add hook for Extbase -> to handle records modified through @@ -45,18 +45,10 @@ TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin( 'Codappix.' . $extension, - 'Results', - ['Search' => 'results'], + 'Search', ['Search' => 'results'] ); - TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin( - 'Codappix.' . $extension, - 'Form', - ['Search' => 'form'], - ['Search' => 'form'] - ); - \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPageTSConfig( '' ); @@ -65,10 +57,10 @@ (isset($configuration['disable.']['elasticsearch']) && filter_var($configuration['disable.']['elasticsearch'], FILTER_VALIDATE_BOOLEAN) === false) ) { - \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\Object\Container\Container::class) - ->registerImplementation( - \Codappix\SearchCore\Connection\ConnectionInterface::class, - \Codappix\SearchCore\Connection\Elasticsearch::class - ); + $container = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\Object\Container\Container::class); + $container->registerImplementation( + \Codappix\SearchCore\Connection\ConnectionInterface::class, + \Codappix\SearchCore\Connection\Elasticsearch::class + ); } }, $_EXTKEY, $_EXTCONF); From ef43bc167421f7e694822cdd512c7c70a6e763a0 Mon Sep 17 00:00:00 2001 From: Benjamin Serfhos Date: Mon, 29 Oct 2018 17:22:41 +0100 Subject: [PATCH 42/73] [FEATURE] Use interface for SearchService Added cached proxy service for data interaction --- Classes/Controller/SearchController.php | 26 ++++--------- Classes/Domain/Search/CachedSearchService.php | 7 +++- Classes/Domain/Search/SearchService.php | 2 +- .../Domain/Search/SearchServiceInterface.php | 39 +++++++++++++++++++ ext_localconf.php | 4 ++ 5 files changed, 58 insertions(+), 20 deletions(-) create mode 100644 Classes/Domain/Search/SearchServiceInterface.php diff --git a/Classes/Controller/SearchController.php b/Classes/Controller/SearchController.php index 3f125046..8ef0f0cd 100644 --- a/Classes/Controller/SearchController.php +++ b/Classes/Controller/SearchController.php @@ -22,7 +22,7 @@ */ use Codappix\SearchCore\Domain\Model\SearchRequest; -use Codappix\SearchCore\Domain\Search\CachedSearchService; +use Codappix\SearchCore\Domain\Search\SearchServiceInterface; use TYPO3\CMS\Extbase\Mvc\Controller\ActionController; /** @@ -31,21 +31,24 @@ class SearchController extends ActionController { /** - * @var CachedSearchService + * @var SearchServiceInterface */ protected $searchService; /** - * @param CachedSearchService $searchService + * @param SearchServiceInterface $searchService */ - public function __construct(CachedSearchService $searchService) + public function __construct(SearchServiceInterface $searchService) { $this->searchService = $searchService; parent::__construct(); } - public function initializeSearchAction() + /** + * Allow dynamic properties in search request + */ + public function initializeResultsAction() { if (isset($this->settings['searching']['mode']) && $this->settings['searching']['mode'] === 'filter' @@ -63,23 +66,10 @@ public function initializeSearchAction() } } - /** - * Display results and deliver original request and result to view. - */ - public function formAction(SearchRequest $searchRequest = null) - { - $this->action($searchRequest); - } - /** * Display results and deliver original request and result to view. */ public function resultsAction(SearchRequest $searchRequest = null) - { - $this->action($searchRequest); - } - - private function action(SearchRequest $searchRequest = null) { $searchResult = null; if ($searchRequest !== null) { diff --git a/Classes/Domain/Search/CachedSearchService.php b/Classes/Domain/Search/CachedSearchService.php index 48a16140..db94c841 100644 --- a/Classes/Domain/Search/CachedSearchService.php +++ b/Classes/Domain/Search/CachedSearchService.php @@ -29,7 +29,7 @@ * Service: Cached Search * @package Codappix\SearchCore\Domain\Search */ -class CachedSearchService implements SingletonInterface +class CachedSearchService implements SingletonInterface, SearchServiceInterface { /** * @var array @@ -55,6 +55,11 @@ public function search(SearchRequestInterface $searchRequest): SearchResultInter return $this->results[$hash] = $this->searchService->search($searchRequest); } + public function processResult(SearchResultInterface $searchResult): SearchResultInterface + { + return $this->searchService->processResult($searchResult); + } + protected function getHash(SearchRequestInterface $searchRequest): string { if (is_callable([$searchRequest, 'getRequestHash'])) { diff --git a/Classes/Domain/Search/SearchService.php b/Classes/Domain/Search/SearchService.php index 01c6f1b6..fedf09e9 100644 --- a/Classes/Domain/Search/SearchService.php +++ b/Classes/Domain/Search/SearchService.php @@ -35,7 +35,7 @@ /** * Service to process a search request. */ -class SearchService +class SearchService implements SearchServiceInterface { /** * @var ConnectionInterface diff --git a/Classes/Domain/Search/SearchServiceInterface.php b/Classes/Domain/Search/SearchServiceInterface.php new file mode 100644 index 00000000..fafb06b4 --- /dev/null +++ b/Classes/Domain/Search/SearchServiceInterface.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. + */ + +use Codappix\SearchCore\Connection\SearchRequestInterface; +use Codappix\SearchCore\Connection\SearchResultInterface; + +/** + * Service to process a search request. + */ +interface SearchServiceInterface +{ + + public function search(SearchRequestInterface $searchRequest): SearchResultInterface; + + /** + * Processes the result, e.g. applies configured data processing to result. + */ + public function processResult(SearchResultInterface $searchResult): SearchResultInterface; +} diff --git a/ext_localconf.php b/ext_localconf.php index 8452ac8a..ef4accda 100644 --- a/ext_localconf.php +++ b/ext_localconf.php @@ -62,5 +62,9 @@ \Codappix\SearchCore\Connection\ConnectionInterface::class, \Codappix\SearchCore\Connection\Elasticsearch::class ); + $container->registerImplementation( + \Codappix\SearchCore\Domain\Search\SearchServiceInterface::class, + \Codappix\SearchCore\Domain\Search\CachedSearchService::class + ); } }, $_EXTKEY, $_EXTCONF); From 615d24b126e9624d467b09d1ca3f972fc691090f Mon Sep 17 00:00:00 2001 From: Benjamin Serfhos Date: Tue, 30 Oct 2018 09:18:29 +0100 Subject: [PATCH 43/73] [TASK] Update unit tests for renaming controller initialize --- Tests/Unit/Controller/SearchControllerTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Tests/Unit/Controller/SearchControllerTest.php b/Tests/Unit/Controller/SearchControllerTest.php index 0357b868..ba1d2af7 100644 --- a/Tests/Unit/Controller/SearchControllerTest.php +++ b/Tests/Unit/Controller/SearchControllerTest.php @@ -76,7 +76,7 @@ public function searchRequestArgumentIsAddedIfModeIsFilterAndArgumentDoesNotExis ] ]); - $this->subject->initializeSearchAction(); + $this->subject->initializeResultsAction(); $this->assertInstanceOf( SearchRequest::class, $this->request->getArgument('searchRequest'), @@ -100,7 +100,7 @@ public function searchRequestArgumentIsAddedToExistingArguments() ] ]); - $this->subject->initializeSearchAction(); + $this->subject->initializeResultsAction(); $this->assertInstanceOf( SearchRequest::class, $this->request->getArgument('searchRequest'), @@ -120,7 +120,7 @@ public function searchRequestArgumentIsNotAddedIfModeIsNotFilter() { $this->inject($this->subject, 'settings', ['searching' => []]); - $this->subject->initializeSearchAction(); + $this->subject->initializeResultsAction(); $this->assertFalse( $this->request->hasArgument('searchRequest'), 'Search request should not exist.' From 3a2c700ff1a7ff43cca8e7d6c9b5f210cd0168c0 Mon Sep 17 00:00:00 2001 From: Benjamin Serfhos Date: Tue, 30 Oct 2018 09:19:05 +0100 Subject: [PATCH 44/73] [TASK] Remove unused constant --- Configuration/TypoScript/constants.typoscript | 1 - 1 file changed, 1 deletion(-) diff --git a/Configuration/TypoScript/constants.typoscript b/Configuration/TypoScript/constants.typoscript index c6b22c6f..7ff92dbc 100644 --- a/Configuration/TypoScript/constants.typoscript +++ b/Configuration/TypoScript/constants.typoscript @@ -6,7 +6,6 @@ plugin.tx_searchcore { } settings { - searchOverview = connections { elasticsearch { host = localhost From ee1f235c2e63778ec37a2fd45f6ac31298aef886 Mon Sep 17 00:00:00 2001 From: Benjamin Serfhos Date: Tue, 30 Oct 2018 09:50:26 +0100 Subject: [PATCH 45/73] [TASK] Use filter interface for custom added filter --- .../Filter/FrontendUserAccessFilter.php | 22 ++--- .../Filter/InvalidSearchFilterException.php | 26 ++++++ .../Search/Filter/SearchFilterInterface.php | 33 +++++++ Classes/Domain/Search/QueryFactory.php | 87 +++++++++++-------- Configuration/TypoScript/setup.typoscript | 4 +- .../20181028-user-access-indexed.rst | 6 +- .../20181030-custom-class-filter.rst | 29 +++++++ 7 files changed, 154 insertions(+), 53 deletions(-) rename Classes/{Hook => Domain/Search}/Filter/FrontendUserAccessFilter.php (78%) create mode 100644 Classes/Domain/Search/Filter/InvalidSearchFilterException.php create mode 100644 Classes/Domain/Search/Filter/SearchFilterInterface.php create mode 100644 Documentation/source/changelog/20181030-custom-class-filter.rst diff --git a/Classes/Hook/Filter/FrontendUserAccessFilter.php b/Classes/Domain/Search/Filter/FrontendUserAccessFilter.php similarity index 78% rename from Classes/Hook/Filter/FrontendUserAccessFilter.php rename to Classes/Domain/Search/Filter/FrontendUserAccessFilter.php index e96276f4..42f9d2c3 100644 --- a/Classes/Hook/Filter/FrontendUserAccessFilter.php +++ b/Classes/Domain/Search/Filter/FrontendUserAccessFilter.php @@ -1,6 +1,6 @@ @@ -25,26 +25,28 @@ /** * Filter: FrontendUserAccess - * @package Codappix\SearchCore\Hook\Filter */ -class FrontendUserAccessFilter +class FrontendUserAccessFilter implements SearchFilterInterface { - /** - * @param array $parameters - * @return void - */ - public function generate($parameters) + public function add(array $query, array $config, $value): array { - $this->appendQueryWithAccessFilter($parameters['query'], $parameters['value']); + return $this->addAccessFilter($query, $value); } - protected function appendQueryWithAccessFilter(array &$query, string $field) + /** + * Add simple boolean lookup for filtering on access groups + */ + protected function addAccessFilter(array $query, string $field): array { $query['query']['bool']['must'][] = [ 'terms' => [$field => $this->getUserGroups()] ]; + return $query; } + /** + * Get inherited user groups from logged in user or simulated user + */ protected function getUserGroups(): array { $feUser = $this->getFrontendUserAuthentication(); diff --git a/Classes/Domain/Search/Filter/InvalidSearchFilterException.php b/Classes/Domain/Search/Filter/InvalidSearchFilterException.php new file mode 100644 index 00000000..7199c58f --- /dev/null +++ b/Classes/Domain/Search/Filter/InvalidSearchFilterException.php @@ -0,0 +1,26 @@ + + * + * 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 InvalidSearchFilterException extends \InvalidArgumentException +{ +} diff --git a/Classes/Domain/Search/Filter/SearchFilterInterface.php b/Classes/Domain/Search/Filter/SearchFilterInterface.php new file mode 100644 index 00000000..fa781d6e --- /dev/null +++ b/Classes/Domain/Search/Filter/SearchFilterInterface.php @@ -0,0 +1,33 @@ + + * + * 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. + */ + +interface SearchFilterInterface +{ + /** + * @param array $query + * @param array $config + * @param mixed $value + * @return array Adjusted $query + */ + public function add(array $query, array $config, $value): array; +} diff --git a/Classes/Domain/Search/QueryFactory.php b/Classes/Domain/Search/QueryFactory.php index 66eaf16b..0c0969fa 100644 --- a/Classes/Domain/Search/QueryFactory.php +++ b/Classes/Domain/Search/QueryFactory.php @@ -25,8 +25,12 @@ use Codappix\SearchCore\Configuration\ConfigurationUtility; use Codappix\SearchCore\Configuration\InvalidArgumentException; use Codappix\SearchCore\Connection\SearchRequestInterface; +use Codappix\SearchCore\Domain\Search\Filter\InvalidSearchFilterException; +use Codappix\SearchCore\Domain\Search\Filter\SearchFilterInterface; use TYPO3\CMS\Core\Utility\ArrayUtility; use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\CMS\Extbase\Object\ObjectManagerInterface; +use TYPO3\CMS\Extbase\Utility\DebuggerUtility; class QueryFactory { @@ -45,14 +49,21 @@ class QueryFactory */ protected $configurationUtility; + /** + * @var ObjectManagerInterface + */ + protected $objectManager; + public function __construct( \TYPO3\CMS\Core\Log\LogManager $logManager, ConfigurationContainerInterface $configuration, - ConfigurationUtility $configurationUtility + ConfigurationUtility $configurationUtility, + ObjectManagerInterface $objectManager ) { $this->logger = $logManager->getLogger(__CLASS__); $this->configuration = $configuration; $this->configurationUtility = $configurationUtility; + $this->objectManager = $objectManager; } /** @@ -231,50 +242,50 @@ protected function addFilters(SearchRequestInterface $searchRequest, array &$que protected function addFilter(string $name, $value, array $config, array &$query): array { - if (!empty($config)) { - if ($config['type'] && $config['type'] === 'user') { - if (!isset($config['userFunc'])) { - throw new MissingAttributeException('No userFunc configured for filter type: user', 1539876182018); - } - - $parameters = [ - 'config' => $config, - 'value' => $value, - 'query' => &$query, - ]; - GeneralUtility::callUserFunction($config['userFunc'], $parameters, $this); - } else { - $filter = []; - if (isset($config['fields'])) { - foreach ($config['fields'] as $elasticField => $inputField) { - $filter[$elasticField] = $value[$inputField]; - } - } - - if (isset($config['raw'])) { - $filter = array_merge($config['raw'], $filter); - } - - if ($config['type'] === 'range') { - $query['query']['bool']['filter'][] = [ - 'range' => [ - $config['field'] => $filter - ] - ]; - } else { - $query['query']['bool']['filter'][] = [ - $config['field'] => $filter - ]; - } - } - } else { + if (empty($config)) { + // Fallback on default term query when no added configuration $query['query']['bool']['filter'][] = [ 'term' => [ $name => $value ] ]; + return $query; } + if ($config['custom'] && $config['type'] === 'custom') { + $customFilter = $this->objectManager->get($config['custom']); + if (!($customFilter instanceof SearchFilterInterface)) { + throw new InvalidSearchFilterException( + 'Custom filter (' . $config['custom'] . ') not instance of SearchFilterInterface', + 1539876182018 + ); + } + + return $customFilter->add($query, $config, $value); + } + + $filter = []; + if (isset($config['fields'])) { + foreach ($config['fields'] as $elasticField => $inputField) { + $filter[$elasticField] = $value[$inputField]; + } + } + + if (isset($config['raw'])) { + $filter = array_merge($config['raw'], $filter); + } + + if ($config['type'] === 'range') { + $query['query']['bool']['filter'][] = [ + 'range' => [ + $config['field'] => $filter + ] + ]; + } else { + $query['query']['bool']['filter'][] = [ + $config['field'] => $filter + ]; + } return $query; } diff --git a/Configuration/TypoScript/setup.typoscript b/Configuration/TypoScript/setup.typoscript index 981d0336..671a071c 100644 --- a/Configuration/TypoScript/setup.typoscript +++ b/Configuration/TypoScript/setup.typoscript @@ -47,8 +47,8 @@ plugin.tx_searchcore { mapping { filter { frontendUserAccess { - type = user - userFunc = Codappix\SearchCore\Hook\Filter\FrontendUserAccessFilter->generate + type = custom + custom = Codappix\SearchCore\Domain\Search\Filter\FrontendUserAccessFilter } } } diff --git a/Documentation/source/changelog/20181028-user-access-indexed.rst b/Documentation/source/changelog/20181028-user-access-indexed.rst index 966dacb0..2456e1ae 100644 --- a/Documentation/source/changelog/20181028-user-access-indexed.rst +++ b/Documentation/source/changelog/20181028-user-access-indexed.rst @@ -1,5 +1,5 @@ Feature "Added frontend user authentication access" -=============================================================== +=================================================== Indexation added based on page access via ``fe_group`` and inherited from ```extendToSubpages```. @@ -7,8 +7,8 @@ from ```extendToSubpages```. The searching is added via typoscript using the UserFunc filter:: frontendUserAccess { - type = user - userFunc = Codappix\SearchCore\Hook\Filter\FrontendUserAccessFilter->generate + type = custom + custom = Codappix\SearchCore\Domain\Search\Filter\FrontendUserAccessFilter } To bypass this filter simply unset default filter in searching.filter diff --git a/Documentation/source/changelog/20181030-custom-class-filter.rst b/Documentation/source/changelog/20181030-custom-class-filter.rst new file mode 100644 index 00000000..07a305db --- /dev/null +++ b/Documentation/source/changelog/20181030-custom-class-filter.rst @@ -0,0 +1,29 @@ +Feature "Manipulate search filter" +================================== + +You can manipulate the filter via a custom class through the ``custom`` type typoscript +mapping.:: + + plugin.tx_searchcore.settings.searching { + mapping { + filter { + frontendUserAccess { + type = custom + custom = Codappix\SearchCore\Domain\Search\Filter\FrontendUserAccessFilter + } + } + } + } + +If you want to force this filter on searching make sure to define them as default filters like::: + + plugin.tx_searchcore.settings.searching { + filter { + frontendUserAccess = search_access + } + } + +Example +------- +See ``Codappix\SearchCore\Domain\Search\Filter\FrontendUserAccessFilter`` as example. + From b63168b8b71d28409cb6f9fc2ec6e6f7b5611091 Mon Sep 17 00:00:00 2001 From: Benjamin Serfhos Date: Tue, 30 Oct 2018 09:59:20 +0100 Subject: [PATCH 46/73] [TASK] Remove unneeded pluginNamespace --- Configuration/TypoScript/setup.typoscript | 3 --- 1 file changed, 3 deletions(-) diff --git a/Configuration/TypoScript/setup.typoscript b/Configuration/TypoScript/setup.typoscript index 671a071c..f3429aea 100644 --- a/Configuration/TypoScript/setup.typoscript +++ b/Configuration/TypoScript/setup.typoscript @@ -1,8 +1,5 @@ plugin.tx_searchcore { view { - # This sets the plugin namespace of all your plugins inside the extension to "tx_searchcore", - # making it possible to directly access search_core parameters in your controller: - pluginNamespace = tx_searchcore templateRootPaths.10 = {$plugin.tx_searchcore.view.templateRootPath} partialRootPaths.10 = {$plugin.tx_searchcore.view.partialRootPath} layoutRootPaths.10 = {$plugin.tx_searchcore.view.layoutRootPath} From 2e327db47c24bc2b3a56c73cbb1f7ccd8c50130d Mon Sep 17 00:00:00 2001 From: Benjamin Serfhos Date: Tue, 30 Oct 2018 10:03:10 +0100 Subject: [PATCH 47/73] [TASK] Finetune QueryFactoryTest based on changes --- Tests/Unit/Domain/Search/QueryFactoryTest.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Tests/Unit/Domain/Search/QueryFactoryTest.php b/Tests/Unit/Domain/Search/QueryFactoryTest.php index 45b77a99..6b11d1a9 100644 --- a/Tests/Unit/Domain/Search/QueryFactoryTest.php +++ b/Tests/Unit/Domain/Search/QueryFactoryTest.php @@ -28,6 +28,7 @@ use Codappix\SearchCore\Domain\Model\SearchRequest; use Codappix\SearchCore\Domain\Search\QueryFactory; use Codappix\SearchCore\Tests\Unit\AbstractUnitTestCase; +use TYPO3\CMS\Extbase\Object\ObjectManagerInterface; class QueryFactoryTest extends AbstractUnitTestCase { @@ -41,13 +42,21 @@ class QueryFactoryTest extends AbstractUnitTestCase */ protected $configuration; + /** + * @var ObjectManagerInterface + */ + protected $objectManager; + public function setUp() { parent::setUp(); $this->configuration = $this->getMockBuilder(ConfigurationContainerInterface::class)->getMock(); $configurationUtility = new ConfigurationUtility(); - $this->subject = new QueryFactory($this->getMockedLogger(), $this->configuration, $configurationUtility); + $this->objectManager = $this->getMockBuilder(ObjectManagerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->subject = new QueryFactory($this->getMockedLogger(), $this->configuration, $configurationUtility, $this->objectManager); } /** From 4f7ccef2f6335b84dd9ac894e2f8752078532aa8 Mon Sep 17 00:00:00 2001 From: Benjamin Serfhos Date: Tue, 30 Oct 2018 13:33:14 +0100 Subject: [PATCH 48/73] [TASK] Apply CGL changes --- Tests/Unit/Command/IndexCommandControllerTest.php | 5 ++++- Tests/Unit/Domain/Search/QueryFactoryTest.php | 7 ++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Tests/Unit/Command/IndexCommandControllerTest.php b/Tests/Unit/Command/IndexCommandControllerTest.php index e3c1e77d..7a18f055 100644 --- a/Tests/Unit/Command/IndexCommandControllerTest.php +++ b/Tests/Unit/Command/IndexCommandControllerTest.php @@ -234,7 +234,10 @@ public function indexerSkipsAndOutputsNonExistingIdentifier() $this->indexerFactory->expects($this->exactly(2)) ->method('getIndexer') ->withConsecutive(['nonExisting'], ['allowedTable']) - ->will($this->onConsecutiveCalls($this->throwException(new NoMatchingIndexerException), $this->returnValue($indexerMock))); + ->will($this->onConsecutiveCalls( + $this->throwException(new NoMatchingIndexerException), + $this->returnValue($indexerMock) + )); $this->subject->indexCommand('nonExisting, allowedTable'); } diff --git a/Tests/Unit/Domain/Search/QueryFactoryTest.php b/Tests/Unit/Domain/Search/QueryFactoryTest.php index 6b11d1a9..e647003c 100644 --- a/Tests/Unit/Domain/Search/QueryFactoryTest.php +++ b/Tests/Unit/Domain/Search/QueryFactoryTest.php @@ -56,7 +56,12 @@ public function setUp() $this->objectManager = $this->getMockBuilder(ObjectManagerInterface::class) ->disableOriginalConstructor() ->getMock(); - $this->subject = new QueryFactory($this->getMockedLogger(), $this->configuration, $configurationUtility, $this->objectManager); + $this->subject = new QueryFactory( + $this->getMockedLogger(), + $this->configuration, + $configurationUtility, + $this->objectManager + ); } /** From 4da6e2fec703ca5ebe6ccaec78d7f461d0bbcdf7 Mon Sep 17 00:00:00 2001 From: Benjamin Serfhos Date: Wed, 31 Oct 2018 09:40:33 +0100 Subject: [PATCH 49/73] [TASK] Add a little description howto extend configuration --- Documentation/source/development/configuration.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/source/development/configuration.rst b/Documentation/source/development/configuration.rst index fc061ba8..ba976c70 100644 --- a/Documentation/source/development/configuration.rst +++ b/Documentation/source/development/configuration.rst @@ -3,6 +3,12 @@ Using custom (non-typoscript) configuration =========================================== +When you are in need of your own non-typoscript configuration, you can create your own +Configuration Container using the TYPO3 Dependency Injection handler. + +Example: Configuration through LocalConfiguration.php +----------------------------------------------------- + Configure your custom ext_localconf.php:: \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\Object\Container\Container::class) From 8531f26410baa75558e776d6b0fbc91dd0316fb6 Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Thu, 27 Dec 2018 11:56:02 +0100 Subject: [PATCH 50/73] BUGFIX: Keep default action non cacheable Otherwise user input is saved and re displayed to foreign visitors. If someone is in need for an cached version, he can create a plugin inside his sitepackage with a different plugin signature but same action. If that does not work, we might add another action for caching. Also keep old action name to be non breaking. --- Classes/Controller/SearchController.php | 4 ++-- ext_localconf.php | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Classes/Controller/SearchController.php b/Classes/Controller/SearchController.php index 8ef0f0cd..1cdd7992 100644 --- a/Classes/Controller/SearchController.php +++ b/Classes/Controller/SearchController.php @@ -48,7 +48,7 @@ public function __construct(SearchServiceInterface $searchService) /** * Allow dynamic properties in search request */ - public function initializeResultsAction() + public function initializeSearchAction() { if (isset($this->settings['searching']['mode']) && $this->settings['searching']['mode'] === 'filter' @@ -69,7 +69,7 @@ public function initializeResultsAction() /** * Display results and deliver original request and result to view. */ - public function resultsAction(SearchRequest $searchRequest = null) + public function searchAction(SearchRequest $searchRequest = null) { $searchResult = null; if ($searchRequest !== null) { diff --git a/ext_localconf.php b/ext_localconf.php index ef4accda..419495e4 100644 --- a/ext_localconf.php +++ b/ext_localconf.php @@ -46,7 +46,8 @@ TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin( 'Codappix.' . $extension, 'Search', - ['Search' => 'results'] + ['Search' => 'search'], + ['Search' => 'search'] ); \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPageTSConfig( From 6f34ca273b04a7a87168a47369a889dfacf7fbb8 Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Thu, 27 Dec 2018 11:57:58 +0100 Subject: [PATCH 51/73] BUGFIX: Keep necessary type hint for extbase --- Classes/Domain/Model/SearchRequest.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Classes/Domain/Model/SearchRequest.php b/Classes/Domain/Model/SearchRequest.php index 17911f6f..fa05904b 100644 --- a/Classes/Domain/Model/SearchRequest.php +++ b/Classes/Domain/Model/SearchRequest.php @@ -91,6 +91,11 @@ public function getSearchTerm(): string return $this->query; } + /** + * Type hint necessary for extbase! + * + * @param array $filter + */ public function setFilter(array $filter) { $filter = ArrayUtility::removeArrayEntryByValue($filter, ''); From 9c2db0b5ba36544e0319228a3ce2a6db69441a28 Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Sat, 29 Dec 2018 17:59:23 +0100 Subject: [PATCH 52/73] TASK: Remove custom filter for fe group filtering As this didn't work on first use. Also no tests are available for this feature yet. As we remove the whole feature in a single commit, we can revert this commit later. This way we can upgrade Elasticsearch and provide this feature later on. --- .../Domain/Index/TcaIndexer/PagesIndexer.php | 38 ---------- .../Index/TcaIndexer/TcaTableService.php | 13 ---- .../Filter/FrontendUserAccessFilter.php | 74 ------------------- .../Filter/InvalidSearchFilterException.php | 26 ------- .../Search/Filter/SearchFilterInterface.php | 33 --------- Classes/Domain/Search/QueryFactory.php | 14 ---- Configuration/TypoScript/setup.typoscript | 13 ---- .../20181028-user-access-indexed.rst | 14 ---- .../20181030-custom-class-filter.rst | 29 -------- 9 files changed, 254 deletions(-) delete mode 100644 Classes/Domain/Search/Filter/FrontendUserAccessFilter.php delete mode 100644 Classes/Domain/Search/Filter/InvalidSearchFilterException.php delete mode 100644 Classes/Domain/Search/Filter/SearchFilterInterface.php delete mode 100644 Documentation/source/changelog/20181028-user-access-indexed.rst delete mode 100644 Documentation/source/changelog/20181030-custom-class-filter.rst diff --git a/Classes/Domain/Index/TcaIndexer/PagesIndexer.php b/Classes/Domain/Index/TcaIndexer/PagesIndexer.php index 1718cb85..5c1bca47 100644 --- a/Classes/Domain/Index/TcaIndexer/PagesIndexer.php +++ b/Classes/Domain/Index/TcaIndexer/PagesIndexer.php @@ -66,9 +66,6 @@ protected function prepareRecord(array &$record) { parent::prepareRecord($record); - // Override access from parent rootline - $record['search_access'] = $this->fetchAccess($record['uid'], (array)$record['search_access']); - $possibleTitleFields = ['nav_title', 'tx_tqseo_pagetitle_rel', 'title']; foreach ($possibleTitleFields as $searchTitleField) { if (isset($record[$searchTitleField]) && trim($record[$searchTitleField])) { @@ -140,41 +137,6 @@ protected function fetchMediaForPage(int $uid): array return $this->fetchSysFileReferenceUids($uid, 'pages', 'media'); } - protected function fetchAccess(int $uid, array $pageAccess): array - { - try { - $rootline = $this->objectManager->get(RootlineUtility::class, $uid)->get(); - } catch (\RuntimeException $e) { - $this->logger->notice( - sprintf('Could not fetch rootline for page %u, because: %s', $uid, $e->getMessage()), - [$pageAccess, $e] - ); - return $pageAccess; - } - - $access = [$pageAccess]; - $extended = false; - foreach ($rootline as $pageInRootLine) { - if ($pageInRootLine['extendToSubpages'] && (!empty($pageInRootLine['fe_group']))) { - $extended = true; - $access[] = GeneralUtility::intExplode( - ',', - $pageInRootLine['fe_group'], - true - ); - } - } - - // Return combined rootline extended access and return unique id's - $access = array_unique(array_merge(...$access)); - - // Remove public value if fe_group is extended to this page - if ($extended && ($key = array_search(0, $access, true)) !== false) { - unset($access[$key]); - } - return array_values($access); - } - protected function fetchSysFileReferenceUids(int $uid, string $tablename, string $fieldname): array { $imageRelationUids = []; diff --git a/Classes/Domain/Index/TcaIndexer/TcaTableService.php b/Classes/Domain/Index/TcaIndexer/TcaTableService.php index ab5c70c9..8e5cde9c 100644 --- a/Classes/Domain/Index/TcaIndexer/TcaTableService.php +++ b/Classes/Domain/Index/TcaIndexer/TcaTableService.php @@ -146,19 +146,6 @@ public function prepareRecord(array &$record) if (isset($record[$this->tca['ctrl']['label']]) && !isset($record['search_title'])) { $record['search_title'] = $record[$this->tca['ctrl']['label']]; } - - if (isset( - $this->tca['ctrl']['enablecolumns']['fe_group'], - $record[$this->tca['ctrl']['enablecolumns']['fe_group']] - )) { - $groups = GeneralUtility::intExplode( - ',', - $record[$this->tca['ctrl']['enablecolumns']['fe_group']], - true - ); - // Always fallback on public visibility when configured - $record['search_access'] = !empty($groups) ? $groups : [0]; - } } protected function getWhereClause(): Where diff --git a/Classes/Domain/Search/Filter/FrontendUserAccessFilter.php b/Classes/Domain/Search/Filter/FrontendUserAccessFilter.php deleted file mode 100644 index 42f9d2c3..00000000 --- a/Classes/Domain/Search/Filter/FrontendUserAccessFilter.php +++ /dev/null @@ -1,74 +0,0 @@ - - * - * 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\Frontend\Authentication\FrontendUserAuthentication; - -/** - * Filter: FrontendUserAccess - */ -class FrontendUserAccessFilter implements SearchFilterInterface -{ - public function add(array $query, array $config, $value): array - { - return $this->addAccessFilter($query, $value); - } - - /** - * Add simple boolean lookup for filtering on access groups - */ - protected function addAccessFilter(array $query, string $field): array - { - $query['query']['bool']['must'][] = [ - 'terms' => [$field => $this->getUserGroups()] - ]; - return $query; - } - - /** - * Get inherited user groups from logged in user or simulated user - */ - protected function getUserGroups(): array - { - $feUser = $this->getFrontendUserAuthentication(); - if ($feUser !== null) { - // If groups is not yet rendered, make sure the group data are fetched - if (!isset($feUser->groupData['uid'])) { - $feUser->fetchGroupData(); - } - - $values = $feUser->groupData['uid']; - if (!empty($values)) { - // Add public content with values - return array_merge([0], $values); - } - } - - // Fallback on public content - return [0]; - } - - protected function getFrontendUserAuthentication(): FrontendUserAuthentication - { - return $GLOBALS['TSFE']->fe_user ?? null; - } -} diff --git a/Classes/Domain/Search/Filter/InvalidSearchFilterException.php b/Classes/Domain/Search/Filter/InvalidSearchFilterException.php deleted file mode 100644 index 7199c58f..00000000 --- a/Classes/Domain/Search/Filter/InvalidSearchFilterException.php +++ /dev/null @@ -1,26 +0,0 @@ - - * - * 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 InvalidSearchFilterException extends \InvalidArgumentException -{ -} diff --git a/Classes/Domain/Search/Filter/SearchFilterInterface.php b/Classes/Domain/Search/Filter/SearchFilterInterface.php deleted file mode 100644 index fa781d6e..00000000 --- a/Classes/Domain/Search/Filter/SearchFilterInterface.php +++ /dev/null @@ -1,33 +0,0 @@ - - * - * 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. - */ - -interface SearchFilterInterface -{ - /** - * @param array $query - * @param array $config - * @param mixed $value - * @return array Adjusted $query - */ - public function add(array $query, array $config, $value): array; -} diff --git a/Classes/Domain/Search/QueryFactory.php b/Classes/Domain/Search/QueryFactory.php index 0c0969fa..f34befc9 100644 --- a/Classes/Domain/Search/QueryFactory.php +++ b/Classes/Domain/Search/QueryFactory.php @@ -25,8 +25,6 @@ use Codappix\SearchCore\Configuration\ConfigurationUtility; use Codappix\SearchCore\Configuration\InvalidArgumentException; use Codappix\SearchCore\Connection\SearchRequestInterface; -use Codappix\SearchCore\Domain\Search\Filter\InvalidSearchFilterException; -use Codappix\SearchCore\Domain\Search\Filter\SearchFilterInterface; use TYPO3\CMS\Core\Utility\ArrayUtility; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Extbase\Object\ObjectManagerInterface; @@ -252,18 +250,6 @@ protected function addFilter(string $name, $value, array $config, array &$query) return $query; } - if ($config['custom'] && $config['type'] === 'custom') { - $customFilter = $this->objectManager->get($config['custom']); - if (!($customFilter instanceof SearchFilterInterface)) { - throw new InvalidSearchFilterException( - 'Custom filter (' . $config['custom'] . ') not instance of SearchFilterInterface', - 1539876182018 - ); - } - - return $customFilter->add($query, $config, $value); - } - $filter = []; if (isset($config['fields'])) { foreach ($config['fields'] as $elasticField => $inputField) { diff --git a/Configuration/TypoScript/setup.typoscript b/Configuration/TypoScript/setup.typoscript index f3429aea..7ff8d295 100644 --- a/Configuration/TypoScript/setup.typoscript +++ b/Configuration/TypoScript/setup.typoscript @@ -36,19 +36,6 @@ plugin.tx_searchcore { # Default query fields (leave empty for all) query = } - - filter { - frontendUserAccess = search_access - } - - mapping { - filter { - frontendUserAccess { - type = custom - custom = Codappix\SearchCore\Domain\Search\Filter\FrontendUserAccessFilter - } - } - } } } } diff --git a/Documentation/source/changelog/20181028-user-access-indexed.rst b/Documentation/source/changelog/20181028-user-access-indexed.rst deleted file mode 100644 index 2456e1ae..00000000 --- a/Documentation/source/changelog/20181028-user-access-indexed.rst +++ /dev/null @@ -1,14 +0,0 @@ -Feature "Added frontend user authentication access" -=================================================== - -Indexation added based on page access via ``fe_group`` and inherited -from ```extendToSubpages```. - -The searching is added via typoscript using the UserFunc filter:: - - frontendUserAccess { - type = custom - custom = Codappix\SearchCore\Domain\Search\Filter\FrontendUserAccessFilter - } - -To bypass this filter simply unset default filter in searching.filter diff --git a/Documentation/source/changelog/20181030-custom-class-filter.rst b/Documentation/source/changelog/20181030-custom-class-filter.rst deleted file mode 100644 index 07a305db..00000000 --- a/Documentation/source/changelog/20181030-custom-class-filter.rst +++ /dev/null @@ -1,29 +0,0 @@ -Feature "Manipulate search filter" -================================== - -You can manipulate the filter via a custom class through the ``custom`` type typoscript -mapping.:: - - plugin.tx_searchcore.settings.searching { - mapping { - filter { - frontendUserAccess { - type = custom - custom = Codappix\SearchCore\Domain\Search\Filter\FrontendUserAccessFilter - } - } - } - } - -If you want to force this filter on searching make sure to define them as default filters like::: - - plugin.tx_searchcore.settings.searching { - filter { - frontendUserAccess = search_access - } - } - -Example -------- -See ``Codappix\SearchCore\Domain\Search\Filter\FrontendUserAccessFilter`` as example. - From 18cb95b8e95a7e778fdca0571f23fe413a3ebe28 Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Sat, 29 Dec 2018 18:01:25 +0100 Subject: [PATCH 53/73] TASK: Update elasticsearch even further Use latest stable 6.x releases, for elasticsearch and used library. --- .travis.yml | 2 +- composer.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index d4f07e29..28afd5ea 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,7 @@ addons: packages: - oracle-java8-set-default before_install: - - curl -O https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-6.4.1.deb && sudo dpkg -i --force-confnew elasticsearch-6.4.1.deb && sudo service elasticsearch restart + - curl -O https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-6.5.4.deb && sudo dpkg -i --force-confnew elasticsearch-6.5.4.deb && sudo service elasticsearch restart - mysql -u root -e 'GRANT ALL ON `typo3_ci_ft%`.* TO travis@127.0.0.1;' language: php diff --git a/composer.json b/composer.json index 07a679f5..3ad4242b 100644 --- a/composer.json +++ b/composer.json @@ -18,7 +18,7 @@ "require": { "php": ">=7.0.0", "typo3/cms": ">= 8.7.0 < 9.0.0", - "ruflin/elastica": "^6.0.2" + "ruflin/elastica": "^6.1.0" }, "require-dev": { "phpunit/phpunit": "~6.4.4", From ea8b4f45386235e1ad3141078c113e90b0d910cb Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Sat, 29 Dec 2018 18:03:14 +0100 Subject: [PATCH 54/73] TASK: Fix / improve some comments * Add missing throws annotation. * Remove useless comments. * Import namespaces used in comments. --- Classes/Configuration/ConfigurationContainer.php | 4 +++- Classes/Connection/Elasticsearch/DocumentFactory.php | 4 ---- Classes/Connection/Elasticsearch/SearchResult.php | 2 ++ Classes/Domain/Search/SearchServiceInterface.php | 4 +++- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Classes/Configuration/ConfigurationContainer.php b/Classes/Configuration/ConfigurationContainer.php index a491c308..b213c9ba 100644 --- a/Classes/Configuration/ConfigurationContainer.php +++ b/Classes/Configuration/ConfigurationContainer.php @@ -26,7 +26,7 @@ /** * Container of all configurations for extension. - * Always inject this to have a single place for configuration and parsing only once. + * Always inject this to have a single place for configuration. */ class ConfigurationContainer implements ConfigurationContainerInterface { @@ -39,6 +39,8 @@ class ConfigurationContainer implements ConfigurationContainerInterface /** * Inject settings via ConfigurationManager. + * + * @throws NoConfigurationException */ public function injectConfigurationManager(ConfigurationManagerInterface $configurationManager) { diff --git a/Classes/Connection/Elasticsearch/DocumentFactory.php b/Classes/Connection/Elasticsearch/DocumentFactory.php index d5707892..9b8fcf0c 100644 --- a/Classes/Connection/Elasticsearch/DocumentFactory.php +++ b/Classes/Connection/Elasticsearch/DocumentFactory.php @@ -44,8 +44,6 @@ public function injectLogger(\TYPO3\CMS\Core\Log\LogManager $logManager) } /** - * Creates document from document. - * * @throws \InvalidArgumentException If no search identifier was provided. */ public function getDocument(string $documentType, array $document): \Elastica\Document @@ -67,8 +65,6 @@ public function getDocument(string $documentType, array $document): \Elastica\Do } /** - * Creates documents based on documents. - * * @throws \InvalidArgumentException If no search identifier was provided. */ public function getDocuments(string $documentType, array $documents): array diff --git a/Classes/Connection/Elasticsearch/SearchResult.php b/Classes/Connection/Elasticsearch/SearchResult.php index 1704f2d7..f178c681 100644 --- a/Classes/Connection/Elasticsearch/SearchResult.php +++ b/Classes/Connection/Elasticsearch/SearchResult.php @@ -21,6 +21,8 @@ * 02110-1301, USA. */ +use Codappix\SearchCore\Connection\FacetInterface; +use Codappix\SearchCore\Connection\ResultItemInterface; use Codappix\SearchCore\Connection\SearchRequestInterface; use Codappix\SearchCore\Connection\SearchResultInterface; use Codappix\SearchCore\Domain\Model\QueryResultInterfaceStub; diff --git a/Classes/Domain/Search/SearchServiceInterface.php b/Classes/Domain/Search/SearchServiceInterface.php index fafb06b4..977a6f60 100644 --- a/Classes/Domain/Search/SearchServiceInterface.php +++ b/Classes/Domain/Search/SearchServiceInterface.php @@ -29,7 +29,9 @@ */ interface SearchServiceInterface { - + /** + * Fetches result for provided search request. + */ public function search(SearchRequestInterface $searchRequest): SearchResultInterface; /** From 13cd87019f443051c65d046394c5d5aa1ba12bef Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Sat, 29 Dec 2018 18:05:24 +0100 Subject: [PATCH 55/73] TASK: Refactor type handling for elasticsearch With V6 of elasticsearch the meaning / handling of index and type has changed, and it will change further in the future. We therefore move code to own classes and adjust / refactor calling code. --- Classes/Connection/Elasticsearch.php | 48 ++++++++----------- .../Elasticsearch/MappingFactory.php | 20 ++++++-- .../Connection/Elasticsearch/TypeFactory.php | 24 +++++++++- .../Elasticsearch/MappingFactoryTest.php | 43 +++++++++++------ 4 files changed, 84 insertions(+), 51 deletions(-) diff --git a/Classes/Connection/Elasticsearch.php b/Classes/Connection/Elasticsearch.php index c7e85041..8d6f2325 100644 --- a/Classes/Connection/Elasticsearch.php +++ b/Classes/Connection/Elasticsearch.php @@ -24,6 +24,7 @@ use Codappix\SearchCore\Connection\Elasticsearch\SearchResult; use Codappix\SearchCore\Domain\Search\QueryFactory; use Elastica\Query; +use Elastica\Type; use TYPO3\CMS\Core\SingletonInterface as Singleton; use TYPO3\CMS\Extbase\Object\ObjectManagerInterface; @@ -118,7 +119,7 @@ public function addDocument(string $documentType, array $document) { $this->withType( $documentType, - function ($type) use ($documentType, $document) { + function (Type $type, string $documentType) use ($document) { $type->addDocument($this->documentFactory->getDocument($documentType, $document)); } ); @@ -129,7 +130,7 @@ public function deleteDocument(string $documentType, string $identifier) try { $this->withType( $documentType, - function ($type) use ($identifier) { + function (Type $type, string $documentType) use ($identifier) { $type->deleteById($identifier); } ); @@ -145,7 +146,7 @@ public function updateDocument(string $documentType, array $document) { $this->withType( $documentType, - function ($type) use ($documentType, $document) { + function (Type $type, string $documentType) use ($document) { $type->updateDocument($this->documentFactory->getDocument($documentType, $document)); } ); @@ -155,7 +156,7 @@ public function addDocuments(string $documentType, array $documents) { $this->withType( $documentType, - function ($type) use ($documentType, $documents) { + function (Type $type, string $documentType) use ($documents) { $type->addDocuments($this->documentFactory->getDocuments($documentType, $documents)); } ); @@ -205,23 +206,6 @@ public function deleteIndexByQuery(Query $query) } } - /** - * Execute given callback with Elastica Type based on provided documentType - */ - protected function withType(string $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, $documentType)->send(); - $callback($type); - $type->getIndex()->refresh(); - } - public function search(SearchRequestInterface $searchRequest): SearchResultInterface { $this->logger->debug('Search for', [$searchRequest->getSearchTerm()]); @@ -233,14 +217,20 @@ public function search(SearchRequestInterface $searchRequest): SearchResultInter return $this->objectManager->get(SearchResult::class, $searchRequest, $search->search()); } - protected function getType($documentType): \Elastica\Type + /** + * Execute given callback with Elastica Type based on provided documentType + */ + private function withType(string $documentType, callable $callback) { - return $this->typeFactory->getType( - $this->indexFactory->getIndex( - $this->connection, - $documentType - ), - 'document' - ); + $type = $this->typeFactory->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($documentType)->send(); + $callback($type, $documentType); + $type->getIndex()->refresh(); } } diff --git a/Classes/Connection/Elasticsearch/MappingFactory.php b/Classes/Connection/Elasticsearch/MappingFactory.php index 8076593f..a1edcff4 100644 --- a/Classes/Connection/Elasticsearch/MappingFactory.php +++ b/Classes/Connection/Elasticsearch/MappingFactory.php @@ -35,29 +35,39 @@ class MappingFactory implements Singleton */ protected $configuration; + /** + * @var TypeFactory + */ + protected $typeFactory; + /** * @param ConfigurationContainerInterface $configuration */ - public function __construct(ConfigurationContainerInterface $configuration) - { + public function __construct( + ConfigurationContainerInterface $configuration, + TypeFactory $typeFactory + ) { $this->configuration = $configuration; + $this->typeFactory = $typeFactory; } /** * Get an mapping based on type. */ - public function getMapping(\Elastica\Type $type, string $documentType = null): \Elastica\Type\Mapping + public function getMapping(string $documentType): \Elastica\Type\Mapping { + $type = $this->typeFactory->getType($documentType); + $mapping = new \Elastica\Type\Mapping(); $mapping->setType($type); - $configuration = $this->getConfiguration($documentType ?? $type->getName()); + $configuration = $this->getConfiguration($documentType); $mapping->setProperties($configuration); return $mapping; } - protected function getConfiguration(string $identifier): array + private function getConfiguration(string $identifier): array { try { return $this->configuration->get('indexing.' . $identifier . '.mapping'); diff --git a/Classes/Connection/Elasticsearch/TypeFactory.php b/Classes/Connection/Elasticsearch/TypeFactory.php index d14fb681..92cc6a1e 100644 --- a/Classes/Connection/Elasticsearch/TypeFactory.php +++ b/Classes/Connection/Elasticsearch/TypeFactory.php @@ -21,6 +21,7 @@ * 02110-1301, USA. */ +use Codappix\SearchCore\Connection\Elasticsearch\IndexFactory; use TYPO3\CMS\Core\SingletonInterface as Singleton; /** @@ -30,11 +31,30 @@ */ class TypeFactory implements Singleton { + /** + * @var IndexFactory + */ + protected $indexFactory; + + /** + * @var Connection + */ + private $connection; + + public function __construct( + Connection $connection, + IndexFactory $indexFactory + ) { + $this->indexFactory = $indexFactory; + $this->connection = $connection; + } + /** * Get an index bases on TYPO3 table name. */ - public function getType(\Elastica\Index $index, string $documentType): \Elastica\Type + public function getType(string $documentType): \Elastica\Type { - return $index->getType($documentType); + $index = $this->indexFactory->getIndex($this->connection, $documentType); + return $index->getType('document'); } } diff --git a/Tests/Unit/Connection/Elasticsearch/MappingFactoryTest.php b/Tests/Unit/Connection/Elasticsearch/MappingFactoryTest.php index 2be69a92..d2c89c98 100644 --- a/Tests/Unit/Connection/Elasticsearch/MappingFactoryTest.php +++ b/Tests/Unit/Connection/Elasticsearch/MappingFactoryTest.php @@ -23,7 +23,9 @@ use Codappix\SearchCore\Configuration\ConfigurationContainerInterface; use Codappix\SearchCore\Connection\Elasticsearch\MappingFactory; +use Codappix\SearchCore\Connection\Elasticsearch\TypeFactory; use Codappix\SearchCore\Tests\Unit\AbstractUnitTestCase; +use Elastica\Type; class MappingFactoryTest extends AbstractUnitTestCase { @@ -32,12 +34,24 @@ class MappingFactoryTest extends AbstractUnitTestCase */ protected $subject; + /** + * @var ConfigurationContainerInterface + */ + protected $configurationMock; + + /** + * @var TypeFactory + */ + protected $typeFactoryMock; + public function setUp() { parent::setUp(); - $this->configuration = $this->getMockBuilder(ConfigurationContainerInterface::class)->getMock(); - $this->subject = new MappingFactory($this->configuration); + $this->configurationMock = $this->getMockBuilder(ConfigurationContainerInterface::class)->getMock(); + $this->typeFactoryMock = $this->getMockBuilder(TypeFactory::class)->disableOriginalConstructor()->getMock(); + + $this->subject = new MappingFactory($this->configurationMock, $this->typeFactoryMock); } /** @@ -45,28 +59,27 @@ public function setUp() */ public function typoScriptConfigurationIsProvidedToIndex() { - $indexName = 'someIndex'; + $documentType = 'someDocument'; $configuration = [ 'channel' => [ 'type' => 'keyword', ], ]; - $type = $this->getMockBuilder(\Elastica\Type::class) - ->disableOriginalConstructor() - ->getMock(); - $type->expects($this->any()) - ->method('getName') - ->willReturn($indexName); - $this->configuration->expects($this->once()) + + $typeMock = $this->getMockBuilder(Type::class)->disableOriginalConstructor()->getMock(); + + $this->typeFactoryMock->expects($this->any()) + ->method('getType') + ->with($documentType) + ->willReturn($typeMock); + $this->configurationMock->expects($this->once()) ->method('get') - ->with('indexing.' . $indexName . '.mapping') + ->with('indexing.' . $documentType . '.mapping') ->willReturn($configuration); - $mapping = $this->subject->getMapping($type)->toArray()[$indexName]; + $mapping = $this->subject->getMapping($documentType)->toArray()['']; $this->assertArraySubset( - [ - 'channel' => $configuration['channel'] - ], + $configuration, $mapping['properties'], true, 'Configuration for properties was not set for mapping.' From a858d748eec66300c0489db6917f51ef405520be Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Sat, 29 Dec 2018 18:06:26 +0100 Subject: [PATCH 56/73] TASK: Shorten code * Do not use variable, instead provide result to method call. * Do not provide public method which is not part of API. Otherwise one might use it in custom PHP code and switch connection later on. Then the method call will no longer work. --- Classes/Connection/Elasticsearch.php | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/Classes/Connection/Elasticsearch.php b/Classes/Connection/Elasticsearch.php index 8d6f2325..81e12584 100644 --- a/Classes/Connection/Elasticsearch.php +++ b/Classes/Connection/Elasticsearch.php @@ -179,17 +179,16 @@ public function deleteIndex() public function deleteIndexByDocumentType(string $documentType) { - $query = Query::create([ + $this->deleteIndexByQuery(Query::create([ 'query' => [ 'term' => [ - 'search_document_type' => $documentType - ] - ] - ]); - $this->deleteIndexByQuery($query); + 'search_document_type' => $documentType, + ], + ], + ])); } - public function deleteIndexByQuery(Query $query) + private function deleteIndexByQuery(Query $query) { $index = $this->connection->getClient()->getIndex($this->indexFactory->getIndexName()); if (!$index->exists()) { From 564ca1511c1b8dcacc20b7fae7eb4ef9dc7c7fe5 Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Sat, 29 Dec 2018 18:07:25 +0100 Subject: [PATCH 57/73] TASK: Refactor code into common flow As we have the same flow in some more places, we refactor this part to follow this conventions. --- .../Connection/Elasticsearch/SearchResult.php | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/Classes/Connection/Elasticsearch/SearchResult.php b/Classes/Connection/Elasticsearch/SearchResult.php index f178c681..cd3db0a1 100644 --- a/Classes/Connection/Elasticsearch/SearchResult.php +++ b/Classes/Connection/Elasticsearch/SearchResult.php @@ -121,14 +121,17 @@ protected function initFacets() } $this->facets = []; - if ($this->result->hasAggregations()) { - foreach ($this->result->getAggregations() as $aggregationName => $aggregation) { - $this->facets[$aggregationName] = $this->objectManager->get( - Facet::class, - $aggregationName, - $aggregation - ); - } + + if ($this->result->hasAggregations() === false) { + return; + } + + foreach ($this->result->getAggregations() as $aggregationName => $aggregation) { + $this->facets[$aggregationName] = $this->objectManager->get( + Facet::class, + $aggregationName, + $aggregation + ); } } From 12c3623dff824ea675fec3bea173d45bf1a31a92 Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Sat, 29 Dec 2018 18:08:00 +0100 Subject: [PATCH 58/73] TASK: Cleanup TypoScript Do not provide unnecessary Constants or Setup. Fluid paths are there out of the box and integrators have all freedom without the provided constants. --- Configuration/TypoScript/constants.typoscript | 6 ------ Configuration/TypoScript/setup.typoscript | 8 -------- 2 files changed, 14 deletions(-) diff --git a/Configuration/TypoScript/constants.typoscript b/Configuration/TypoScript/constants.typoscript index 7ff92dbc..136d4dda 100644 --- a/Configuration/TypoScript/constants.typoscript +++ b/Configuration/TypoScript/constants.typoscript @@ -1,10 +1,4 @@ plugin.tx_searchcore { - view { - templateRootPath = EXT:search_core/Resources/Private/Templates - partialRootPath = EXT:search_core/Resources/Private/Partials - layoutRootPath = EXT:search_core/Resources/Private/Layouts - } - settings { connections { elasticsearch { diff --git a/Configuration/TypoScript/setup.typoscript b/Configuration/TypoScript/setup.typoscript index 7ff8d295..dd31866b 100644 --- a/Configuration/TypoScript/setup.typoscript +++ b/Configuration/TypoScript/setup.typoscript @@ -1,13 +1,5 @@ plugin.tx_searchcore { - view { - templateRootPaths.10 = {$plugin.tx_searchcore.view.templateRootPath} - partialRootPaths.10 = {$plugin.tx_searchcore.view.partialRootPath} - layoutRootPaths.10 = {$plugin.tx_searchcore.view.layoutRootPath} - } - settings { - searchOverview = {$plugin.tx_searchcore.settings.searchOverview} - connections { elasticsearch { host = {$plugin.tx_searchcore.settings.connections.elasticsearch.host} From 89a558e73589ab0b517f2b385cf185e8c9b25c18 Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Sat, 29 Dec 2018 18:44:38 +0100 Subject: [PATCH 59/73] TASK: Improve documentation * Add some missing documentation. * Adjust some documentation due to breaking changes. * Adjust structure of documentation for easier changelog rendering and browsing. --- Classes/Command/IndexCommandController.php | 4 +-- Documentation/source/changelog.rst | 18 ++-------- Documentation/source/changelog/0.0.8.rst | 16 +++++++++ .../20180306-120-facet-configuration.rst | 0 .../20180308-131-respect-page-cache-clear.rst | 0 .../20180308-introduce-php70-type-hints.rst | 0 .../20180309-25-provide-sys-language-uid.rst | 0 ...15-134-make-conent-fields-configurable.rst | 0 .../20180410-148-keep-sys_language_uid.rst | 0 ...t-relation-resolver-to-data-processing.rst | 0 ...180518-75-make-index-name-configurable.rst | 0 ...-allow-zero-as-typoscript-filter-value.rst | 0 ...e-pluginname-in-configurationcontainer.rst | 0 Documentation/source/changelog/0.1.0.rst | 15 ++++++++ .../2018-added-content-element-wizard.rst | 5 +++ .../0.1.0/2018-changed-interfaces.rst | 31 ++++++++++++++++ .../0.1.0/2018-elasticsearch-upgrade.rst | 9 +++++ .../0.1.0/2018-search-service-interface.rst | 23 ++++++++++++ .../20181027-added-flush-command.rst | 0 ...81027-allow-multiple-identifier-on-cli.rst | 13 +++++++ .../20181027-remove-cms7-support.rst | 4 +-- .../20181028-fluid-templating-list-items.rst | 28 +++++++++++++++ ...20181227-rename-of-configuration-files.rst | 6 ++++ ...81027-allow-multiple-identifier-on-cli.rst | 4 --- .../20181028-fluid-templating-list-items.rst | 24 ------------- Documentation/source/configuration.rst | 4 +-- Documentation/source/usage.rst | 35 ++++++++++++++----- 27 files changed, 182 insertions(+), 57 deletions(-) create mode 100644 Documentation/source/changelog/0.0.8.rst rename Documentation/source/changelog/{ => 0.0.8}/20180306-120-facet-configuration.rst (100%) rename Documentation/source/changelog/{ => 0.0.8}/20180308-131-respect-page-cache-clear.rst (100%) rename Documentation/source/changelog/{ => 0.0.8}/20180308-introduce-php70-type-hints.rst (100%) rename Documentation/source/changelog/{ => 0.0.8}/20180309-25-provide-sys-language-uid.rst (100%) rename Documentation/source/changelog/{ => 0.0.8}/20180315-134-make-conent-fields-configurable.rst (100%) rename Documentation/source/changelog/{ => 0.0.8}/20180410-148-keep-sys_language_uid.rst (100%) rename Documentation/source/changelog/{ => 0.0.8}/20180424-149-extract-relation-resolver-to-data-processing.rst (100%) rename Documentation/source/changelog/{ => 0.0.8}/20180518-75-make-index-name-configurable.rst (100%) rename Documentation/source/changelog/{ => 0.0.8}/20180926-163-allow-zero-as-typoscript-filter-value.rst (100%) rename Documentation/source/changelog/{ => 0.0.8}/20181106-170-do-not-specify-the-pluginname-in-configurationcontainer.rst (100%) create mode 100644 Documentation/source/changelog/0.1.0.rst create mode 100644 Documentation/source/changelog/0.1.0/2018-added-content-element-wizard.rst create mode 100644 Documentation/source/changelog/0.1.0/2018-changed-interfaces.rst create mode 100644 Documentation/source/changelog/0.1.0/2018-elasticsearch-upgrade.rst create mode 100644 Documentation/source/changelog/0.1.0/2018-search-service-interface.rst rename Documentation/source/changelog/{ => 0.1.0}/20181027-added-flush-command.rst (100%) create mode 100644 Documentation/source/changelog/0.1.0/20181027-allow-multiple-identifier-on-cli.rst rename Documentation/source/changelog/{ => 0.1.0}/20181027-remove-cms7-support.rst (56%) create mode 100644 Documentation/source/changelog/0.1.0/20181028-fluid-templating-list-items.rst create mode 100644 Documentation/source/changelog/0.1.0/20181227-rename-of-configuration-files.rst delete mode 100644 Documentation/source/changelog/20181027-allow-multiple-identifier-on-cli.rst delete mode 100644 Documentation/source/changelog/20181028-fluid-templating-list-items.rst diff --git a/Classes/Command/IndexCommandController.php b/Classes/Command/IndexCommandController.php index 8e1f370c..dff0fb36 100644 --- a/Classes/Command/IndexCommandController.php +++ b/Classes/Command/IndexCommandController.php @@ -72,7 +72,7 @@ public function deleteCommand(string $identifiers) } /** - * Will delete the full index for given identifiers. + * Will flush the index for given identifiers from backend. * * @param string $identifier Comma separated list of identifiers. */ @@ -80,7 +80,7 @@ public function flushCommand(string $identifiers = 'pages') { $this->executeForIdentifier($identifiers, function (IndexerInterface $indexer) { $indexer->delete(); - $this->outputLine('Indice ' . $indexer->getIdentifier() . ' was deleted.'); + $this->outputLine('Indice ' . $indexer->getIdentifier() . ' was flushed.'); }); } diff --git a/Documentation/source/changelog.rst b/Documentation/source/changelog.rst index 9d226f78..fadb7d28 100644 --- a/Documentation/source/changelog.rst +++ b/Documentation/source/changelog.rst @@ -2,19 +2,7 @@ Changelog ========= .. toctree:: - :maxdepth: 1 - :glob: + :maxdepth: 2 - changelog/20181027-added-flush-command - changelog/20181027-allow-multiple-identifiers-on-cli - changelog/20181027-remove-cms7-support - changelog/20180518-75-make-index-name-configurable - changelog/20180424-149-extract-relation-resolver-to-data-processing - changelog/20180410-148-keep-sys_language_uid - changelog/20180315-134-make-conent-fields-configurable - changelog/20180309-25-provide-sys-language-uid - changelog/20180308-131-respect-page-cache-clear - changelog/20180308-introduce-php70-type-hints - changelog/20180306-120-facet-configuration - changelog/20180926-163-allow-zero-as-typoscript-filter-value - changelog/20181106-170-do-not-specify-the-pluginname-in-configurationcontainer + changelog/0.1.0 + changelog/0.0.8 diff --git a/Documentation/source/changelog/0.0.8.rst b/Documentation/source/changelog/0.0.8.rst new file mode 100644 index 00000000..03ce022a --- /dev/null +++ b/Documentation/source/changelog/0.0.8.rst @@ -0,0 +1,16 @@ +Up till v0.0.8 +============== + +.. toctree:: + :maxdepth: 1 + + 0.0.8/20180306-120-facet-configuration + 0.0.8/20180308-131-respect-page-cache-clear + 0.0.8/20180308-introduce-php70-type-hints + 0.0.8/20180309-25-provide-sys-language-uid + 0.0.8/20180315-134-make-conent-fields-configurable + 0.0.8/20180410-148-keep-sys_language_uid + 0.0.8/20180424-149-extract-relation-resolver-to-data-processing + 0.0.8/20180518-75-make-index-name-configurable + 0.0.8/20180926-163-allow-zero-as-typoscript-filter-value + 0.0.8/20181106-170-do-not-specify-the-pluginname-in-configurationcontainer diff --git a/Documentation/source/changelog/20180306-120-facet-configuration.rst b/Documentation/source/changelog/0.0.8/20180306-120-facet-configuration.rst similarity index 100% rename from Documentation/source/changelog/20180306-120-facet-configuration.rst rename to Documentation/source/changelog/0.0.8/20180306-120-facet-configuration.rst diff --git a/Documentation/source/changelog/20180308-131-respect-page-cache-clear.rst b/Documentation/source/changelog/0.0.8/20180308-131-respect-page-cache-clear.rst similarity index 100% rename from Documentation/source/changelog/20180308-131-respect-page-cache-clear.rst rename to Documentation/source/changelog/0.0.8/20180308-131-respect-page-cache-clear.rst diff --git a/Documentation/source/changelog/20180308-introduce-php70-type-hints.rst b/Documentation/source/changelog/0.0.8/20180308-introduce-php70-type-hints.rst similarity index 100% rename from Documentation/source/changelog/20180308-introduce-php70-type-hints.rst rename to Documentation/source/changelog/0.0.8/20180308-introduce-php70-type-hints.rst diff --git a/Documentation/source/changelog/20180309-25-provide-sys-language-uid.rst b/Documentation/source/changelog/0.0.8/20180309-25-provide-sys-language-uid.rst similarity index 100% rename from Documentation/source/changelog/20180309-25-provide-sys-language-uid.rst rename to Documentation/source/changelog/0.0.8/20180309-25-provide-sys-language-uid.rst diff --git a/Documentation/source/changelog/20180315-134-make-conent-fields-configurable.rst b/Documentation/source/changelog/0.0.8/20180315-134-make-conent-fields-configurable.rst similarity index 100% rename from Documentation/source/changelog/20180315-134-make-conent-fields-configurable.rst rename to Documentation/source/changelog/0.0.8/20180315-134-make-conent-fields-configurable.rst diff --git a/Documentation/source/changelog/20180410-148-keep-sys_language_uid.rst b/Documentation/source/changelog/0.0.8/20180410-148-keep-sys_language_uid.rst similarity index 100% rename from Documentation/source/changelog/20180410-148-keep-sys_language_uid.rst rename to Documentation/source/changelog/0.0.8/20180410-148-keep-sys_language_uid.rst diff --git a/Documentation/source/changelog/20180424-149-extract-relation-resolver-to-data-processing.rst b/Documentation/source/changelog/0.0.8/20180424-149-extract-relation-resolver-to-data-processing.rst similarity index 100% rename from Documentation/source/changelog/20180424-149-extract-relation-resolver-to-data-processing.rst rename to Documentation/source/changelog/0.0.8/20180424-149-extract-relation-resolver-to-data-processing.rst diff --git a/Documentation/source/changelog/20180518-75-make-index-name-configurable.rst b/Documentation/source/changelog/0.0.8/20180518-75-make-index-name-configurable.rst similarity index 100% rename from Documentation/source/changelog/20180518-75-make-index-name-configurable.rst rename to Documentation/source/changelog/0.0.8/20180518-75-make-index-name-configurable.rst diff --git a/Documentation/source/changelog/20180926-163-allow-zero-as-typoscript-filter-value.rst b/Documentation/source/changelog/0.0.8/20180926-163-allow-zero-as-typoscript-filter-value.rst similarity index 100% rename from Documentation/source/changelog/20180926-163-allow-zero-as-typoscript-filter-value.rst rename to Documentation/source/changelog/0.0.8/20180926-163-allow-zero-as-typoscript-filter-value.rst diff --git a/Documentation/source/changelog/20181106-170-do-not-specify-the-pluginname-in-configurationcontainer.rst b/Documentation/source/changelog/0.0.8/20181106-170-do-not-specify-the-pluginname-in-configurationcontainer.rst similarity index 100% rename from Documentation/source/changelog/20181106-170-do-not-specify-the-pluginname-in-configurationcontainer.rst rename to Documentation/source/changelog/0.0.8/20181106-170-do-not-specify-the-pluginname-in-configurationcontainer.rst diff --git a/Documentation/source/changelog/0.1.0.rst b/Documentation/source/changelog/0.1.0.rst new file mode 100644 index 00000000..036a2222 --- /dev/null +++ b/Documentation/source/changelog/0.1.0.rst @@ -0,0 +1,15 @@ +v0.1.0 +====== + +.. toctree:: + :maxdepth: 1 + + 0.1.0/2018-added-content-element-wizard + 0.1.0/2018-changed-interfaces + 0.1.0/2018-elasticsearch-upgrade + 0.1.0/2018-search-service-interface + 0.1.0/20181027-added-flush-command + 0.1.0/20181027-allow-multiple-identifier-on-cli + 0.1.0/20181027-remove-cms7-support + 0.1.0/20181028-fluid-templating-list-items + 0.1.0/20181227-rename-of-configuration-files diff --git a/Documentation/source/changelog/0.1.0/2018-added-content-element-wizard.rst b/Documentation/source/changelog/0.1.0/2018-added-content-element-wizard.rst new file mode 100644 index 00000000..4fc2dac3 --- /dev/null +++ b/Documentation/source/changelog/0.1.0/2018-added-content-element-wizard.rst @@ -0,0 +1,5 @@ +Feature: "Added content element wizard entry" +============================================= + +The search core plugin is now selectable from the content element wizard by default. +Therefore the necessary PageTSConfig is added by default. diff --git a/Documentation/source/changelog/0.1.0/2018-changed-interfaces.rst b/Documentation/source/changelog/0.1.0/2018-changed-interfaces.rst new file mode 100644 index 00000000..993b7da8 --- /dev/null +++ b/Documentation/source/changelog/0.1.0/2018-changed-interfaces.rst @@ -0,0 +1,31 @@ +Breaking Change "Changed interfaces" +==================================== + +Some interfaces and abstract classes have been adjusted: + +``Codappix\SearchCore\Connection\ConnectionInterface``: + + * New method ``public function deleteIndexByDocumentType(string $documentType);`` + +``Codappix\SearchCore\Domain\Index\IndexerInterface``: + + * New method ``public function deleteDocuments();`` + + * New method ``public function getIdentifier(): string;`` + +``Codappix\SearchCore\Domain\Index\AbstractIndexer``: + + * New method ``abstract public function getDocumentIdentifier($identifier): string;`` + +``Codappix\SearchCore\Connection\SearchRequestInterface``: + + * Changed method signature from ``public function setSearchService(SearchService $searchService);`` + to ``public function setSearchService(SearchServiceInterface $searchService);`` + +Also some exceptions have changed: + +* ``Codappix\SearchCore\Connection\Elasticsearch\DocumentFactory::getDocument()`` now +throws an ``\InvalidArgumentException`` instead of ``\Exception``, if no +``search_identifier`` was provided. + + diff --git a/Documentation/source/changelog/0.1.0/2018-elasticsearch-upgrade.rst b/Documentation/source/changelog/0.1.0/2018-elasticsearch-upgrade.rst new file mode 100644 index 00000000..bfc7e45c --- /dev/null +++ b/Documentation/source/changelog/0.1.0/2018-elasticsearch-upgrade.rst @@ -0,0 +1,9 @@ +Breaking Change "Elasticsearch Upgrade" +======================================= + +By now Elasticsearch v6.x is required in order to work. + +You might need to change some configuration, as this is just piped through to +Elasticsearch. Check out the breaking changes of Elasticsearch from 5.x to 6.x. + +Also update your Elasticsearch instance. diff --git a/Documentation/source/changelog/0.1.0/2018-search-service-interface.rst b/Documentation/source/changelog/0.1.0/2018-search-service-interface.rst new file mode 100644 index 00000000..056bcb3d --- /dev/null +++ b/Documentation/source/changelog/0.1.0/2018-search-service-interface.rst @@ -0,0 +1,23 @@ +Feature "SearchServiceInterface" +================================ + +The concrete search service can now be exchanged. Therefore a new Interface was +introduced:: + + namespace Codappix\SearchCore\Domain\Search; + + use Codappix\SearchCore\Connection\SearchRequestInterface; + use Codappix\SearchCore\Connection\SearchResultInterface; + + interface SearchServiceInterface + { + /** + * Fetches result for provided search request. + */ + public function search(SearchRequestInterface $searchRequest): SearchResultInterface; + + /** + * Processes the result, e.g. applies configured data processing to result. + */ + public function processResult(SearchResultInterface $searchResult): SearchResultInterface; + } diff --git a/Documentation/source/changelog/20181027-added-flush-command.rst b/Documentation/source/changelog/0.1.0/20181027-added-flush-command.rst similarity index 100% rename from Documentation/source/changelog/20181027-added-flush-command.rst rename to Documentation/source/changelog/0.1.0/20181027-added-flush-command.rst diff --git a/Documentation/source/changelog/0.1.0/20181027-allow-multiple-identifier-on-cli.rst b/Documentation/source/changelog/0.1.0/20181027-allow-multiple-identifier-on-cli.rst new file mode 100644 index 00000000..952e12fe --- /dev/null +++ b/Documentation/source/changelog/0.1.0/20181027-allow-multiple-identifier-on-cli.rst @@ -0,0 +1,13 @@ +Breaking Change "Allow multiple identifiers on cli" +=================================================== + +All CLI commands except a comma separated list of IDs now. Still single IDs are allowed. + +Each Identifier will be processed one by another. This is just for continence to not +call the command multiple times with different identifiers. + +Spaces are ignored before and after commas. + + +As the argument was renamed from ``--identifier`` to ``--identifiers``, this is +considered a breaking change. diff --git a/Documentation/source/changelog/20181027-remove-cms7-support.rst b/Documentation/source/changelog/0.1.0/20181027-remove-cms7-support.rst similarity index 56% rename from Documentation/source/changelog/20181027-remove-cms7-support.rst rename to Documentation/source/changelog/0.1.0/20181027-remove-cms7-support.rst index ec493f1d..e62d50e4 100644 --- a/Documentation/source/changelog/20181027-remove-cms7-support.rst +++ b/Documentation/source/changelog/0.1.0/20181027-remove-cms7-support.rst @@ -1,5 +1,5 @@ -Breaking Change "Remove CMS7 support" -===================================== +Breaking Change "Removed CMS7 support" +====================================== We no longer support TYPO3 CMS 7.x. diff --git a/Documentation/source/changelog/0.1.0/20181028-fluid-templating-list-items.rst b/Documentation/source/changelog/0.1.0/20181028-fluid-templating-list-items.rst new file mode 100644 index 00000000..7094ff22 --- /dev/null +++ b/Documentation/source/changelog/0.1.0/20181028-fluid-templating-list-items.rst @@ -0,0 +1,28 @@ +Feature "Added fluid partials for list items" +============================================= + +When using a separate partial for ListItem you can simply adjust for your custom page type: + +Example ListItem.html:: +----------------------- +.. code-block:: html + :linenos: + + + + + Add opening for possible different partials based on Document types: + + + {f:render(partial: 'resultItem-{result.search_document_type}', arguments: {result: result)} + + + // Render pages + + + + // Render custom "documentType" + + + diff --git a/Documentation/source/changelog/0.1.0/20181227-rename-of-configuration-files.rst b/Documentation/source/changelog/0.1.0/20181227-rename-of-configuration-files.rst new file mode 100644 index 00000000..2aa71d8d --- /dev/null +++ b/Documentation/source/changelog/0.1.0/20181227-rename-of-configuration-files.rst @@ -0,0 +1,6 @@ +Breaking Change "Configuration files were renamed" +================================================== + +TypoScript configuration files now end with ``.typoscript`` instead of ``.txt``. + +If you require these files via include statements with full file name, these need to be adjusted. diff --git a/Documentation/source/changelog/20181027-allow-multiple-identifier-on-cli.rst b/Documentation/source/changelog/20181027-allow-multiple-identifier-on-cli.rst deleted file mode 100644 index bab42117..00000000 --- a/Documentation/source/changelog/20181027-allow-multiple-identifier-on-cli.rst +++ /dev/null @@ -1,4 +0,0 @@ -Feature "Allow multiple identifiers on cli" -=========================================== - -All CLI commands except a comma separated list of IDs now. diff --git a/Documentation/source/changelog/20181028-fluid-templating-list-items.rst b/Documentation/source/changelog/20181028-fluid-templating-list-items.rst deleted file mode 100644 index 05501805..00000000 --- a/Documentation/source/changelog/20181028-fluid-templating-list-items.rst +++ /dev/null @@ -1,24 +0,0 @@ -Feature "Added fluid partials for list items" -============================================= - -When using a seperate partial for ListItem you can simply adjust for your custom page type: - -Example ListItem.html:: ------------------------ -.. code-block:: html - :linenos: - - - - - Add opening for possible different partials based on Document types: - - - - {f:render(partial: 'Results/Item/YourDocumentType', arguments: {result: result})} - {f:render(partial: 'Results/Item/Page', arguments: {result: result})} - {f:render(partial: 'Results/Item/Unknown', arguments: {result: result})} - - - diff --git a/Documentation/source/configuration.rst b/Documentation/source/configuration.rst index 53ac469b..78910086 100644 --- a/Documentation/source/configuration.rst +++ b/Documentation/source/configuration.rst @@ -24,11 +24,11 @@ The structure is following TYPO3 Extbase conventions. All settings are placed in Here is the example default configuration that's provided through static include: -.. literalinclude:: ../../Configuration/TypoScript/constants.txt +.. literalinclude:: ../../Configuration/TypoScript/constants.typoscript :language: typoscript :caption: Static TypoScript Constants -.. literalinclude:: ../../Configuration/TypoScript/setup.txt +.. literalinclude:: ../../Configuration/TypoScript/setup.typoscript :language: typoscript :caption: Static TypoScript Setup diff --git a/Documentation/source/usage.rst b/Documentation/source/usage.rst index fc6d08a3..8e0d93c5 100644 --- a/Documentation/source/usage.rst +++ b/Documentation/source/usage.rst @@ -11,12 +11,13 @@ Manual indexing You can trigger indexing from CLI:: - ./typo3/cli_dispatch.phpsh extbase index:index --identifier 'pages' - ./bin/typo3cms index:index --identifier 'pages' + ./typo3/cli_dispatch.phpsh extbase index:index --identifiers 'pages' + ./bin/typo3cms index:index --identifiers 'pages' This will index the table ``pages`` using the :ref:`TcaIndexer`. -Only one index per call is available, to run multiple indexers, just make multiple calls. +Multiple indexer can be called by providing a comma separated list of identifiers as +a single argument. Spaces before and after commas are ignored. The indexers have to be defined in TypoScript via :ref:`configuration_options_index`. .. _usage_manual_deletion: @@ -24,14 +25,32 @@ The indexers have to be defined in TypoScript via :ref:`configuration_options_in Manual deletion --------------- -You can trigger deletion for a single index from CLI:: +You can trigger deletion for indexes from CLI:: - ./typo3/cli_dispatch.phpsh extbase index:delete --identifier 'pages' - ./bin/typo3cms index:delete --identifier 'pages' + ./typo3/cli_dispatch.phpsh extbase index:delete --identifiers 'pages' + ./bin/typo3cms index:delete --identifiers 'pages' -This will delete the index for the table ``pages``. +This will delete the index for the table ``pages``. Deletion means removing all +documents from the index. -Only one delete per call is available, to run multiple deletions, just make multiple calls. +Multiple indices can be called by providing a comma separated list of identifiers as +a single argument. Spaces before and after commas are ignored. + +.. _usage_manual_flush: + +Manual flush +------------ + +You can trigger flush for indexes from CLI:: + + ./typo3/cli_dispatch.phpsh extbase index:flush --identifiers 'pages' + ./bin/typo3cms index:flush --identifiers 'pages' + +This will flush the index for the table ``pages``. Flush means removing the index +from backend. + +Multiple indices can be called by providing a comma separated list of identifiers as +a single argument. Spaces before and after commas are ignored. .. _usage_auto_indexing: From 831da6a4e46abfe62c82c9a0d97774a1f4099184 Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Sat, 29 Dec 2018 19:21:58 +0100 Subject: [PATCH 60/73] TASK: Use new SearchRequestInterface everywhere Otherwise the interface is no big benefit. Also it might crash under some circumstances. --- Classes/Connection/SearchRequestInterface.php | 4 ++-- Classes/Domain/Model/SearchRequest.php | 8 ++++---- Tests/Unit/Domain/Model/SearchRequestTest.php | 7 +++---- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/Classes/Connection/SearchRequestInterface.php b/Classes/Connection/SearchRequestInterface.php index d6778862..221f078d 100644 --- a/Classes/Connection/SearchRequestInterface.php +++ b/Classes/Connection/SearchRequestInterface.php @@ -21,7 +21,7 @@ * 02110-1301, USA. */ -use Codappix\SearchCore\Domain\Search\SearchService; +use Codappix\SearchCore\Domain\Search\SearchServiceInterface; use TYPO3\CMS\Extbase\Persistence\QueryInterface; interface SearchRequestInterface extends QueryInterface @@ -54,5 +54,5 @@ public function setConnection(ConnectionInterface $connection); * Workaround for paginate widget support which will * use the request to build another search. */ - public function setSearchService(SearchService $searchService); + public function setSearchService(SearchServiceInterface $searchService); } diff --git a/Classes/Domain/Model/SearchRequest.php b/Classes/Domain/Model/SearchRequest.php index fa05904b..0d8865b1 100644 --- a/Classes/Domain/Model/SearchRequest.php +++ b/Classes/Domain/Model/SearchRequest.php @@ -25,7 +25,7 @@ use Codappix\SearchCore\Connection\FacetRequestInterface; use Codappix\SearchCore\Connection\SearchRequestInterface; use Codappix\SearchCore\Connection\SearchResultInterface; -use Codappix\SearchCore\Domain\Search\SearchService; +use Codappix\SearchCore\Domain\Search\SearchServiceInterface; use Codappix\SearchCore\Utility\ArrayUtility as CustomArrayUtility; use TYPO3\CMS\Core\Utility\ArrayUtility; @@ -69,7 +69,7 @@ class SearchRequest implements SearchRequestInterface protected $connection; /** - * @var SearchService + * @var SearchServiceInterface */ protected $searchService; @@ -137,7 +137,7 @@ public function setConnection(ConnectionInterface $connection) $this->connection = $connection; } - public function setSearchService(SearchService $searchService) + public function setSearchService(SearchServiceInterface $searchService) { $this->searchService = $searchService; } @@ -156,7 +156,7 @@ public function execute($returnRawQueryResult = false) 1502197732 ); } - if (!($this->searchService instanceof SearchService)) { + if (!($this->searchService instanceof SearchServiceInterface)) { throw new \InvalidArgumentException( 'SearchService was not set before, therefore execute can not work. Use `setSearchService` before.', 1520325175 diff --git a/Tests/Unit/Domain/Model/SearchRequestTest.php b/Tests/Unit/Domain/Model/SearchRequestTest.php index 9dcc3139..30e24959 100644 --- a/Tests/Unit/Domain/Model/SearchRequestTest.php +++ b/Tests/Unit/Domain/Model/SearchRequestTest.php @@ -24,7 +24,7 @@ use Codappix\SearchCore\Connection\ConnectionInterface; use Codappix\SearchCore\Connection\SearchResultInterface; use Codappix\SearchCore\Domain\Model\SearchRequest; -use Codappix\SearchCore\Domain\Search\SearchService; +use Codappix\SearchCore\Domain\Search\SearchServiceInterface; use Codappix\SearchCore\Tests\Unit\AbstractUnitTestCase; class SearchRequestTest extends AbstractUnitTestCase @@ -105,7 +105,7 @@ public function exceptionIsThrownIfConnectionWasNotSet() { $subject = new SearchRequest(); $subject->setSearchService( - $this->getMockBuilder(SearchService::class) + $this->getMockBuilder(SearchServiceInterface::class) ->disableOriginalConstructor() ->getMock() ); @@ -118,8 +118,7 @@ public function exceptionIsThrownIfConnectionWasNotSet() */ public function executionMakesUseOfProvidedConnectionAndSearchService() { - $searchServiceMock = $this->getMockBuilder(SearchService::class) - ->disableOriginalConstructor() + $searchServiceMock = $this->getMockBuilder(SearchServiceInterface::class) ->getMock(); $connectionMock = $this->getMockBuilder(ConnectionInterface::class) ->getMock(); From f95723fff74cb62f7d37a9f68270f514c896c20c Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Sat, 29 Dec 2018 19:23:46 +0100 Subject: [PATCH 61/73] TASK: Fix unit tests --- Tests/Unit/Command/IndexCommandControllerTest.php | 2 +- Tests/Unit/Controller/SearchControllerTest.php | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Tests/Unit/Command/IndexCommandControllerTest.php b/Tests/Unit/Command/IndexCommandControllerTest.php index 7a18f055..d722f6df 100644 --- a/Tests/Unit/Command/IndexCommandControllerTest.php +++ b/Tests/Unit/Command/IndexCommandControllerTest.php @@ -131,7 +131,7 @@ public function flushIsPossible() ->willReturn('pages'); $this->subject->expects($this->once()) ->method('outputLine') - ->with('Indice pages was deleted.'); + ->with('Indice pages was flushed.'); $this->indexerFactory->expects($this->once()) ->method('getIndexer') ->with('pages') diff --git a/Tests/Unit/Controller/SearchControllerTest.php b/Tests/Unit/Controller/SearchControllerTest.php index ba1d2af7..0357b868 100644 --- a/Tests/Unit/Controller/SearchControllerTest.php +++ b/Tests/Unit/Controller/SearchControllerTest.php @@ -76,7 +76,7 @@ public function searchRequestArgumentIsAddedIfModeIsFilterAndArgumentDoesNotExis ] ]); - $this->subject->initializeResultsAction(); + $this->subject->initializeSearchAction(); $this->assertInstanceOf( SearchRequest::class, $this->request->getArgument('searchRequest'), @@ -100,7 +100,7 @@ public function searchRequestArgumentIsAddedToExistingArguments() ] ]); - $this->subject->initializeResultsAction(); + $this->subject->initializeSearchAction(); $this->assertInstanceOf( SearchRequest::class, $this->request->getArgument('searchRequest'), @@ -120,7 +120,7 @@ public function searchRequestArgumentIsNotAddedIfModeIsNotFilter() { $this->inject($this->subject, 'settings', ['searching' => []]); - $this->subject->initializeResultsAction(); + $this->subject->initializeSearchAction(); $this->assertFalse( $this->request->hasArgument('searchRequest'), 'Search request should not exist.' From 97160dac91df53028add8b17df6205a0ee0b8f03 Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Sat, 29 Dec 2018 19:24:07 +0100 Subject: [PATCH 62/73] TASK: Use php 7 anonymous function call --- Configuration/TCA/Overrides/tt_content.php | 8 +++----- ext_localconf.php | 4 ++-- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/Configuration/TCA/Overrides/tt_content.php b/Configuration/TCA/Overrides/tt_content.php index 5bb389a8..de606bb5 100644 --- a/Configuration/TCA/Overrides/tt_content.php +++ b/Configuration/TCA/Overrides/tt_content.php @@ -1,9 +1,7 @@ Date: Sat, 29 Dec 2018 19:27:02 +0100 Subject: [PATCH 63/73] TASK: Remove unused file / php class --- .../Search/MissingAttributeException.php | 26 ------------------- 1 file changed, 26 deletions(-) delete mode 100644 Classes/Domain/Search/MissingAttributeException.php diff --git a/Classes/Domain/Search/MissingAttributeException.php b/Classes/Domain/Search/MissingAttributeException.php deleted file mode 100644 index f47e3695..00000000 --- a/Classes/Domain/Search/MissingAttributeException.php +++ /dev/null @@ -1,26 +0,0 @@ - - * - * 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 MissingAttributeException extends \InvalidArgumentException -{ -} From 43254c168c724ff049afeefa4fbd0795be6ce633 Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Sat, 29 Dec 2018 19:27:47 +0100 Subject: [PATCH 64/73] TASK: Fix license and php doc --- Classes/Domain/Search/CachedSearchService.php | 3 +-- Classes/Utility/ArrayUtility.php | 21 ++++++++++++++++--- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/Classes/Domain/Search/CachedSearchService.php b/Classes/Domain/Search/CachedSearchService.php index db94c841..a8655f3c 100644 --- a/Classes/Domain/Search/CachedSearchService.php +++ b/Classes/Domain/Search/CachedSearchService.php @@ -26,8 +26,7 @@ use TYPO3\CMS\Core\SingletonInterface; /** - * Service: Cached Search - * @package Codappix\SearchCore\Domain\Search + * Service to process a search request, only once per request. */ class CachedSearchService implements SingletonInterface, SearchServiceInterface { diff --git a/Classes/Utility/ArrayUtility.php b/Classes/Utility/ArrayUtility.php index e77c056d..91e9e47c 100644 --- a/Classes/Utility/ArrayUtility.php +++ b/Classes/Utility/ArrayUtility.php @@ -2,10 +2,25 @@ namespace Codappix\SearchCore\Utility; -/** - * Utility: Array - * @package Codappix\SearchCore\Utility +/* + * Copyright (C) 2018 Benjamin Serfhos + * + * 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 ArrayUtility { /** From 28a8dd1ab40751fd60e0f68f4c01c90b35ebe153 Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Sun, 30 Dec 2018 13:22:25 +0100 Subject: [PATCH 65/73] TASK: rephrase indice to index. --- Classes/Command/IndexCommandController.php | 4 ++-- Documentation/source/usage.rst | 4 ++-- Tests/Unit/Command/IndexCommandControllerTest.php | 14 +++++++------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Classes/Command/IndexCommandController.php b/Classes/Command/IndexCommandController.php index dff0fb36..b01800ee 100644 --- a/Classes/Command/IndexCommandController.php +++ b/Classes/Command/IndexCommandController.php @@ -54,7 +54,7 @@ public function indexCommand(string $identifiers) { $this->executeForIdentifier($identifiers, function (IndexerInterface $indexer) { $indexer->indexAllDocuments(); - $this->outputLine('Documents in indice ' . $indexer->getIdentifier() . ' were indexed.'); + $this->outputLine('Documents in index ' . $indexer->getIdentifier() . ' were indexed.'); }); } @@ -67,7 +67,7 @@ public function deleteCommand(string $identifiers) { $this->executeForIdentifier($identifiers, function (IndexerInterface $indexer) { $indexer->deleteDocuments(); - $this->outputLine('Documents in indice ' . $indexer->getIdentifier() . ' were deleted.'); + $this->outputLine('Documents in index ' . $indexer->getIdentifier() . ' were deleted.'); }); } diff --git a/Documentation/source/usage.rst b/Documentation/source/usage.rst index 8e0d93c5..687ae2d0 100644 --- a/Documentation/source/usage.rst +++ b/Documentation/source/usage.rst @@ -33,7 +33,7 @@ You can trigger deletion for indexes from CLI:: This will delete the index for the table ``pages``. Deletion means removing all documents from the index. -Multiple indices can be called by providing a comma separated list of identifiers as +Multiple indexes can be called by providing a comma separated list of identifiers as a single argument. Spaces before and after commas are ignored. .. _usage_manual_flush: @@ -49,7 +49,7 @@ You can trigger flush for indexes from CLI:: This will flush the index for the table ``pages``. Flush means removing the index from backend. -Multiple indices can be called by providing a comma separated list of identifiers as +Multiple indexes can be called by providing a comma separated list of identifiers as a single argument. Spaces before and after commas are ignored. .. _usage_auto_indexing: diff --git a/Tests/Unit/Command/IndexCommandControllerTest.php b/Tests/Unit/Command/IndexCommandControllerTest.php index d722f6df..2b52109b 100644 --- a/Tests/Unit/Command/IndexCommandControllerTest.php +++ b/Tests/Unit/Command/IndexCommandControllerTest.php @@ -85,7 +85,7 @@ public function indexerExecutesForAllowedTable() ->method('quit'); $this->subject->expects($this->once()) ->method('outputLine') - ->with('Documents in indice allowedTable were indexed.'); + ->with('Documents in index allowedTable were indexed.'); $this->indexerFactory->expects($this->once()) ->method('getIndexer') ->with('allowedTable') @@ -107,7 +107,7 @@ public function deletionIsPossible() ->willReturn('allowedTable'); $this->subject->expects($this->once()) ->method('outputLine') - ->with('Documents in indice allowedTable were deleted.'); + ->with('Documents in index allowedTable were deleted.'); $this->indexerFactory->expects($this->once()) ->method('getIndexer') ->with('allowedTable') @@ -131,7 +131,7 @@ public function flushIsPossible() ->willReturn('pages'); $this->subject->expects($this->once()) ->method('outputLine') - ->with('Indice pages was flushed.'); + ->with('Index pages was deleted.'); $this->indexerFactory->expects($this->once()) ->method('getIndexer') ->with('pages') @@ -177,8 +177,8 @@ public function indexerExecutesForAllowedTables() $this->subject->expects($this->exactly(2)) ->method('outputLine') ->withConsecutive( - ['Documents in indice allowedTable were indexed.'], - ['Documents in indice anotherTable were indexed.'] + ['Documents in index allowedTable were indexed.'], + ['Documents in index anotherTable were indexed.'] ); $this->indexerFactory->expects($this->exactly(2)) ->method('getIndexer') @@ -203,7 +203,7 @@ public function indexerSkipsEmptyIdentifier() ->method('quit'); $this->subject->expects($this->once()) ->method('outputLine') - ->with('Documents in indice allowedTable were indexed.'); + ->with('Documents in index allowedTable were indexed.'); $this->indexerFactory->expects($this->once()) ->method('getIndexer') ->with('allowedTable') @@ -229,7 +229,7 @@ public function indexerSkipsAndOutputsNonExistingIdentifier() ->method('outputLine') ->withConsecutive( ['No indexer found for: nonExisting.'], - ['Documents in indice allowedTable were indexed.'] + ['Documents in index allowedTable were indexed.'] ); $this->indexerFactory->expects($this->exactly(2)) ->method('getIndexer') From 689f293194a6bdb935bdf68255a96aa26858be30 Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Sun, 30 Dec 2018 13:43:43 +0100 Subject: [PATCH 66/73] TASK: Finish deletion of index and documents feature We replace the "flush" and "delete" by "delete" and "deletedocuments" logic. This makes it more obvious what will happen, without reading the docs. Also we kept the logic to always provide the index name, as we will need them in the future. Due to elasticsearch v6 changes no types are allowed in the same index in the future. Therefore we need to make it possible to use different indexes in the future, leading to the need to provide the document type all the time. --- Classes/Command/IndexCommandController.php | 10 +-- Classes/Connection/ConnectionInterface.php | 12 +-- Classes/Connection/Elasticsearch.php | 84 +++++++++---------- .../Connection/Elasticsearch/IndexFactory.php | 23 +++-- .../Connection/Elasticsearch/TypeFactory.php | 5 +- Classes/Domain/Index/AbstractIndexer.php | 6 +- Classes/Domain/Index/IndexerInterface.php | 4 +- Documentation/source/changelog/0.1.0.rst | 2 +- .../0.1.0/2018-changed-interfaces.rst | 10 ++- ...027-added-delete-all-documents-command.rst | 11 +++ .../0.1.0/20181027-added-flush-command.rst | 6 -- Documentation/source/usage.rst | 15 ++-- .../Elasticsearch/IndexDeletionTest.php | 6 +- .../Command/IndexCommandControllerTest.php | 10 +-- .../Elasticsearch/IndexFactoryTest.php | 2 +- 15 files changed, 112 insertions(+), 94 deletions(-) create mode 100644 Documentation/source/changelog/0.1.0/20181027-added-delete-all-documents-command.rst delete mode 100644 Documentation/source/changelog/0.1.0/20181027-added-flush-command.rst diff --git a/Classes/Command/IndexCommandController.php b/Classes/Command/IndexCommandController.php index b01800ee..bed8af75 100644 --- a/Classes/Command/IndexCommandController.php +++ b/Classes/Command/IndexCommandController.php @@ -63,24 +63,24 @@ public function indexCommand(string $identifiers) * * @param string $identifier Comma separated list of identifiers. */ - public function deleteCommand(string $identifiers) + public function deleteDocumentsCommand(string $identifiers) { $this->executeForIdentifier($identifiers, function (IndexerInterface $indexer) { - $indexer->deleteDocuments(); + $indexer->deleteAllDocuments(); $this->outputLine('Documents in index ' . $indexer->getIdentifier() . ' were deleted.'); }); } /** - * Will flush the index for given identifiers from backend. + * Will delete the index for given identifiers. * * @param string $identifier Comma separated list of identifiers. */ - public function flushCommand(string $identifiers = 'pages') + public function deleteCommand(string $identifiers = 'pages') { $this->executeForIdentifier($identifiers, function (IndexerInterface $indexer) { $indexer->delete(); - $this->outputLine('Indice ' . $indexer->getIdentifier() . ' was flushed.'); + $this->outputLine('Index ' . $indexer->getIdentifier() . ' was deleted.'); }); } diff --git a/Classes/Connection/ConnectionInterface.php b/Classes/Connection/ConnectionInterface.php index 76122f8b..7677e7c3 100644 --- a/Classes/Connection/ConnectionInterface.php +++ b/Classes/Connection/ConnectionInterface.php @@ -51,17 +51,17 @@ public function updateDocument(string $documentType, array $document); public function deleteDocument(string $documentType, string $identifier); /** - * Search by given request and return result. + * Will all documents of certain kind / in certain index. */ - public function search(SearchRequestInterface $searchRequest): SearchResultInterface; + public function deleteAllDocuments(string $documentType); /** - * Will delete the index / db of defined document type. + * Will delete the whole index / db. */ - public function deleteIndexByDocumentType(string $documentType); + public function deleteIndex(string $documentType); /** - * Will delete the whole index / db. + * Search by given request and return result. */ - public function deleteIndex(); + public function search(SearchRequestInterface $searchRequest): SearchResultInterface; } diff --git a/Classes/Connection/Elasticsearch.php b/Classes/Connection/Elasticsearch.php index 81e12584..0f85058e 100644 --- a/Classes/Connection/Elasticsearch.php +++ b/Classes/Connection/Elasticsearch.php @@ -142,6 +142,29 @@ function (Type $type, string $documentType) use ($identifier) { } } + public function deleteAllDocuments(string $documentType) + { + $this->deleteDocumentsByQuery($documentType, Query::create([ + 'query' => [ + 'term' => [ + 'search_document_type' => $documentType, + ], + ], + ])); + } + + public function deleteIndex(string $documentType) + { + try { + $this->indexFactory->getIndex($this->connection, $documentType)->delete(); + } catch (\InvalidArgumentException $e) { + $this->logger->notice( + 'Index did not exist, therefore was not deleted.', + [$documentType, $e] + ); + } + } + public function updateDocument(string $documentType, array $document) { $this->withType( @@ -162,49 +185,6 @@ function (Type $type, string $documentType) use ($documents) { ); } - public function deleteIndex() - { - $index = $this->connection->getClient()->getIndex($this->indexFactory->getIndexName()); - - if (!$index->exists()) { - $this->logger->notice( - 'Index did not exist, therefore was not deleted.', - [$this->indexFactory->getIndexName()] - ); - return; - } - - $index->delete(); - } - - public function deleteIndexByDocumentType(string $documentType) - { - $this->deleteIndexByQuery(Query::create([ - 'query' => [ - 'term' => [ - 'search_document_type' => $documentType, - ], - ], - ])); - } - - private function deleteIndexByQuery(Query $query) - { - $index = $this->connection->getClient()->getIndex($this->indexFactory->getIndexName()); - if (!$index->exists()) { - $this->logger->notice( - 'Index did not exist, therefore items can not be deleted by query.', - [$this->indexFactory->getIndexName(), $query->getQuery()] - ); - return; - } - $response = $index->deleteByQuery($query); - if ($response->getData()['deleted'] > 0) { - // Refresh index when delete query is invoked - $index->refresh(); - } - } - public function search(SearchRequestInterface $searchRequest): SearchResultInterface { $this->logger->debug('Search for', [$searchRequest->getSearchTerm()]); @@ -232,4 +212,22 @@ private function withType(string $documentType, callable $callback) $callback($type, $documentType); $type->getIndex()->refresh(); } + + private function deleteDocumentsByQuery(string $documentType, Query $query) + { + try { + $index = $this->indexFactory->getIndex($this->connection, $documentType); + $response = $index->deleteByQuery($query); + + if ($response->getData()['deleted'] > 0) { + // Refresh index when delete query is invoked + $index->refresh(); + } + } catch (\InvalidArgumentException $e) { + $this->logger->notice( + 'Index did not exist, therefore items can not be deleted by query.', + [$documentType, $query->getQuery()] + ); + } + } } diff --git a/Classes/Connection/Elasticsearch/IndexFactory.php b/Classes/Connection/Elasticsearch/IndexFactory.php index 2482c0eb..718342fa 100644 --- a/Classes/Connection/Elasticsearch/IndexFactory.php +++ b/Classes/Connection/Elasticsearch/IndexFactory.php @@ -70,22 +70,35 @@ public function getIndexName(): string } /** - * Get an index based on TYPO3 table name. + * @throws \InvalidArgumentException If index does not exist. */ public function getIndex(Connection $connection, string $documentType): \Elastica\Index { $index = $connection->getClient()->getIndex($this->getIndexName()); if ($index->exists() === false) { - $config = $this->getConfigurationFor($documentType); - $this->logger->debug(sprintf('Create index %s.', $documentType), [$documentType, $config]); - $index->create($config); - $this->logger->debug(sprintf('Created index %s.', $documentType), [$documentType]); + throw new \InvalidArgumentException('The requested index does not exist.', 1546173102); } return $index; } + public function createIndex(Connection $connection, string $documentType): \Elastica\Index + { + $index = $connection->getClient()->getIndex($this->getIndexName()); + + if ($index->exists() === true) { + return $index; + } + + $config = $this->getConfigurationFor($documentType); + $this->logger->debug(sprintf('Create index %s.', $documentType), [$documentType, $config]); + $index->create($config); + $this->logger->debug(sprintf('Created index %s.', $documentType), [$documentType]); + + return $index; + } + protected function getConfigurationFor(string $documentType): array { try { diff --git a/Classes/Connection/Elasticsearch/TypeFactory.php b/Classes/Connection/Elasticsearch/TypeFactory.php index 92cc6a1e..8e52eb25 100644 --- a/Classes/Connection/Elasticsearch/TypeFactory.php +++ b/Classes/Connection/Elasticsearch/TypeFactory.php @@ -49,12 +49,9 @@ public function __construct( $this->connection = $connection; } - /** - * Get an index bases on TYPO3 table name. - */ public function getType(string $documentType): \Elastica\Type { - $index = $this->indexFactory->getIndex($this->connection, $documentType); + $index = $this->indexFactory->createIndex($this->connection, $documentType); return $index->getType('document'); } } diff --git a/Classes/Domain/Index/AbstractIndexer.php b/Classes/Domain/Index/AbstractIndexer.php index adb172e4..7eae6156 100644 --- a/Classes/Domain/Index/AbstractIndexer.php +++ b/Classes/Domain/Index/AbstractIndexer.php @@ -106,14 +106,14 @@ public function indexDocument(string $identifier) public function delete() { $this->logger->info('Start deletion of index.'); - $this->connection->deleteIndex(); + $this->connection->deleteIndex($this->getDocumentName()); $this->logger->info('Finish deletion.'); } - public function deleteDocuments() + public function deleteAllDocuments() { $this->logger->info('Start deletion of indexed documents.'); - $this->connection->deleteIndexByDocumentType($this->getDocumentName()); + $this->connection->deleteAllDocuments($this->getDocumentName()); $this->logger->info('Finish deletion.'); } diff --git a/Classes/Domain/Index/IndexerInterface.php b/Classes/Domain/Index/IndexerInterface.php index f413677d..4071ee85 100644 --- a/Classes/Domain/Index/IndexerInterface.php +++ b/Classes/Domain/Index/IndexerInterface.php @@ -42,9 +42,9 @@ public function indexDocument(string $identifier); public function delete(); /** - * Delete the whole index. + * Delete all documents from index. */ - public function deleteDocuments(); + public function deleteAllDocuments(); /** * Receives the identifier of the indexer itself. diff --git a/Documentation/source/changelog/0.1.0.rst b/Documentation/source/changelog/0.1.0.rst index 036a2222..3cfc4cec 100644 --- a/Documentation/source/changelog/0.1.0.rst +++ b/Documentation/source/changelog/0.1.0.rst @@ -8,7 +8,7 @@ v0.1.0 0.1.0/2018-changed-interfaces 0.1.0/2018-elasticsearch-upgrade 0.1.0/2018-search-service-interface - 0.1.0/20181027-added-flush-command + 0.1.0/20181027-added-delete-all-documents-command 0.1.0/20181027-allow-multiple-identifier-on-cli 0.1.0/20181027-remove-cms7-support 0.1.0/20181028-fluid-templating-list-items diff --git a/Documentation/source/changelog/0.1.0/2018-changed-interfaces.rst b/Documentation/source/changelog/0.1.0/2018-changed-interfaces.rst index 993b7da8..669c7765 100644 --- a/Documentation/source/changelog/0.1.0/2018-changed-interfaces.rst +++ b/Documentation/source/changelog/0.1.0/2018-changed-interfaces.rst @@ -5,7 +5,7 @@ Some interfaces and abstract classes have been adjusted: ``Codappix\SearchCore\Connection\ConnectionInterface``: - * New method ``public function deleteIndexByDocumentType(string $documentType);`` + * New method ``public function deleteAllDocuments(string $documentType);`` ``Codappix\SearchCore\Domain\Index\IndexerInterface``: @@ -28,4 +28,12 @@ Also some exceptions have changed: throws an ``\InvalidArgumentException`` instead of ``\Exception``, if no ``search_identifier`` was provided. +* ``Codappix\SearchCore\Connection\Elasticsearch\IndexFactory::getIndex()`` now + throws an ``\InvalidArgumentException`` if the index does not exist. Leaving + handling up to the caller. + Before the index was created if it didn't exist. To create an index, a new method + ``public function createIndex(Connection $connection, string $documentType): \Elastica\Index`` + was added. This method will only create the index if it didn't exist before. + In the end, the index is returned always. Making this method a 1:1 replacement for + older ``getIndex()``. diff --git a/Documentation/source/changelog/0.1.0/20181027-added-delete-all-documents-command.rst b/Documentation/source/changelog/0.1.0/20181027-added-delete-all-documents-command.rst new file mode 100644 index 00000000..22f221a2 --- /dev/null +++ b/Documentation/source/changelog/0.1.0/20181027-added-delete-all-documents-command.rst @@ -0,0 +1,11 @@ +Feature "Added delete documents command" +======================================== + +A new command to delete all documents within an index was added. In contrast to the +existing delete command, this deletes only documents but keeps the index. + +E.g. if your backend is Elasticsearch or a relational database, the index or table is +kept, including structure or mappings, while only the documents or rows are removed. + +In contrast the existing delete command will still remove the index or table itself, +depending on the used connection. diff --git a/Documentation/source/changelog/0.1.0/20181027-added-flush-command.rst b/Documentation/source/changelog/0.1.0/20181027-added-flush-command.rst deleted file mode 100644 index 569865d9..00000000 --- a/Documentation/source/changelog/0.1.0/20181027-added-flush-command.rst +++ /dev/null @@ -1,6 +0,0 @@ -Feature "Added flush command" -============================= - -A new command to flush indices was added. In contrast to the existing delete command, -this one will delete the whole index, while the existing delete command only deletes -all documents within an index. diff --git a/Documentation/source/usage.rst b/Documentation/source/usage.rst index 687ae2d0..b385c556 100644 --- a/Documentation/source/usage.rst +++ b/Documentation/source/usage.rst @@ -36,18 +36,17 @@ documents from the index. Multiple indexes can be called by providing a comma separated list of identifiers as a single argument. Spaces before and after commas are ignored. -.. _usage_manual_flush: +.. _usage_manual_delete_all_documents: -Manual flush ------------- +Manual delete all documents +--------------------------- -You can trigger flush for indexes from CLI:: +You can trigger deletion of all documents for indexes from CLI:: - ./typo3/cli_dispatch.phpsh extbase index:flush --identifiers 'pages' - ./bin/typo3cms index:flush --identifiers 'pages' + ./typo3/cli_dispatch.phpsh extbase index:deletedocuments --identifiers 'pages' + ./bin/typo3cms index:deletedocuments --identifiers 'pages' -This will flush the index for the table ``pages``. Flush means removing the index -from backend. +This will delete all documents within the index for the table ``pages``. Multiple indexes can be called by providing a comma separated list of identifiers as a single argument. Spaces before and after commas are ignored. diff --git a/Tests/Functional/Connection/Elasticsearch/IndexDeletionTest.php b/Tests/Functional/Connection/Elasticsearch/IndexDeletionTest.php index ee14f259..ae277378 100644 --- a/Tests/Functional/Connection/Elasticsearch/IndexDeletionTest.php +++ b/Tests/Functional/Connection/Elasticsearch/IndexDeletionTest.php @@ -89,14 +89,12 @@ public function documentsAreDeleted() $response = $this->client->request('typo3content/_search?q=*:*'); $this->assertSame($response->getData()['hits']['total'], 5, 'Not exactly 5 documents are in index.'); - $contentIndexer->deleteDocuments(); + $contentIndexer->deleteAllDocuments(); $response = $this->client->request('typo3content/_search?q=*:*'); $this->assertSame($response->getData()['hits']['total'], 2, 'Not exactly 2 documents are in index.'); - $pageIndexer->deleteDocuments(); + $pageIndexer->deleteAllDocuments(); $response = $this->client->request('typo3content/_search?q=*:*'); $this->assertSame($response->getData()['hits']['total'], 0, 'Index should be empty.'); - - $index->delete(); } } diff --git a/Tests/Unit/Command/IndexCommandControllerTest.php b/Tests/Unit/Command/IndexCommandControllerTest.php index 2b52109b..69f02bab 100644 --- a/Tests/Unit/Command/IndexCommandControllerTest.php +++ b/Tests/Unit/Command/IndexCommandControllerTest.php @@ -97,7 +97,7 @@ public function indexerExecutesForAllowedTable() /** * @test */ - public function deletionIsPossible() + public function deletionOfDocumentsIsPossible() { $indexerMock = $this->getMockBuilder(TcaIndexer::class) ->disableOriginalConstructor() @@ -114,14 +114,14 @@ public function deletionIsPossible() ->will($this->returnValue($indexerMock)); $indexerMock->expects($this->once()) - ->method('deleteDocuments'); - $this->subject->deleteCommand('allowedTable'); + ->method('deleteAllDocuments'); + $this->subject->deleteDocumentsCommand('allowedTable'); } /** * @test */ - public function flushIsPossible() + public function deletionOfIndexIsPossible() { $indexerMock = $this->getMockBuilder(TcaIndexer::class) ->disableOriginalConstructor() @@ -139,7 +139,7 @@ public function flushIsPossible() $indexerMock->expects($this->once()) ->method('delete'); - $this->subject->flushCommand('pages'); + $this->subject->deleteCommand('pages'); } /** diff --git a/Tests/Unit/Connection/Elasticsearch/IndexFactoryTest.php b/Tests/Unit/Connection/Elasticsearch/IndexFactoryTest.php index 6d80f704..77d5f900 100644 --- a/Tests/Unit/Connection/Elasticsearch/IndexFactoryTest.php +++ b/Tests/Unit/Connection/Elasticsearch/IndexFactoryTest.php @@ -150,6 +150,6 @@ public function typoScriptConfigurationIsProvidedToIndex() ]) ); - $this->subject->getIndex($connection, 'someIndex'); + $this->subject->createIndex($connection, 'someIndex'); } } From 7f2249e3ffbdb643376677b6146b63b998b142c3 Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Sun, 30 Dec 2018 14:00:22 +0100 Subject: [PATCH 67/73] TASK: Use a single array utility Instead of only adding a new class for one static method, we extend the existing class to only import a single class. This way we extend the original array utility function collection. --- Classes/Configuration/ConfigurationContainer.php | 2 +- Classes/Domain/Model/SearchRequest.php | 5 ++--- Classes/Domain/Search/QueryFactory.php | 2 +- Classes/Domain/Search/SearchService.php | 2 +- Classes/Utility/ArrayUtility.php | 4 +++- Documentation/source/development/configuration.rst | 2 +- 6 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Classes/Configuration/ConfigurationContainer.php b/Classes/Configuration/ConfigurationContainer.php index b213c9ba..9917f12d 100644 --- a/Classes/Configuration/ConfigurationContainer.php +++ b/Classes/Configuration/ConfigurationContainer.php @@ -21,7 +21,7 @@ * 02110-1301, USA. */ -use TYPO3\CMS\Core\Utility\ArrayUtility; +use Codappix\SearchCore\Utility\ArrayUtility; use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface; /** diff --git a/Classes/Domain/Model/SearchRequest.php b/Classes/Domain/Model/SearchRequest.php index 0d8865b1..32efb5da 100644 --- a/Classes/Domain/Model/SearchRequest.php +++ b/Classes/Domain/Model/SearchRequest.php @@ -26,8 +26,7 @@ use Codappix\SearchCore\Connection\SearchRequestInterface; use Codappix\SearchCore\Connection\SearchResultInterface; use Codappix\SearchCore\Domain\Search\SearchServiceInterface; -use Codappix\SearchCore\Utility\ArrayUtility as CustomArrayUtility; -use TYPO3\CMS\Core\Utility\ArrayUtility; +use Codappix\SearchCore\Utility\ArrayUtility; /** * Represents a search request used to process an actual search. @@ -99,7 +98,7 @@ public function getSearchTerm(): string public function setFilter(array $filter) { $filter = ArrayUtility::removeArrayEntryByValue($filter, ''); - $this->filter = CustomArrayUtility::removeEmptyElementsRecursively($filter); + $this->filter = ArrayUtility::removeEmptyElementsRecursively($filter); } public function hasFilter(): bool diff --git a/Classes/Domain/Search/QueryFactory.php b/Classes/Domain/Search/QueryFactory.php index f34befc9..c7565b14 100644 --- a/Classes/Domain/Search/QueryFactory.php +++ b/Classes/Domain/Search/QueryFactory.php @@ -25,7 +25,7 @@ use Codappix\SearchCore\Configuration\ConfigurationUtility; use Codappix\SearchCore\Configuration\InvalidArgumentException; use Codappix\SearchCore\Connection\SearchRequestInterface; -use TYPO3\CMS\Core\Utility\ArrayUtility; +use Codappix\SearchCore\Utility\ArrayUtility; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Extbase\Object\ObjectManagerInterface; use TYPO3\CMS\Extbase\Utility\DebuggerUtility; diff --git a/Classes/Domain/Search/SearchService.php b/Classes/Domain/Search/SearchService.php index fedf09e9..43b54b8c 100644 --- a/Classes/Domain/Search/SearchService.php +++ b/Classes/Domain/Search/SearchService.php @@ -29,7 +29,7 @@ use Codappix\SearchCore\DataProcessing\Service as DataProcessorService; use Codappix\SearchCore\Domain\Model\FacetRequest; use Codappix\SearchCore\Domain\Model\SearchResult; -use TYPO3\CMS\Core\Utility\ArrayUtility; +use Codappix\SearchCore\Utility\ArrayUtility; use TYPO3\CMS\Extbase\Object\ObjectManagerInterface; /** diff --git a/Classes/Utility/ArrayUtility.php b/Classes/Utility/ArrayUtility.php index 91e9e47c..29815b15 100644 --- a/Classes/Utility/ArrayUtility.php +++ b/Classes/Utility/ArrayUtility.php @@ -21,7 +21,9 @@ * 02110-1301, USA. */ -class ArrayUtility +use TYPO3\CMS\Core\Utility\ArrayUtility as Typo3ArrayUtility; + +class ArrayUtility extends Typo3ArrayUtility { /** * Recursively removes empty array elements. diff --git a/Documentation/source/development/configuration.rst b/Documentation/source/development/configuration.rst index ba976c70..e9827ff8 100644 --- a/Documentation/source/development/configuration.rst +++ b/Documentation/source/development/configuration.rst @@ -25,7 +25,7 @@ SearchCoreConfigurationContainer.php:: use Codappix\SearchCore\Configuration\ConfigurationContainer; use Codappix\SearchCore\Configuration\NoConfigurationException; - use TYPO3\CMS\Core\Utility\ArrayUtility; + use Codappix\SearchCore\Utility\ArrayUtility; use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface; /** From 09cbaede293d3d9cef4c9f7a15a55f8bbb3a2e4e Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Sun, 30 Dec 2018 14:01:10 +0100 Subject: [PATCH 68/73] TASK: Remove unused code E.g. use statement and injected object manager. --- Classes/Domain/Index/TcaIndexer/PagesIndexer.php | 11 +---------- Classes/Domain/Model/SearchRequest.php | 1 - 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/Classes/Domain/Index/TcaIndexer/PagesIndexer.php b/Classes/Domain/Index/TcaIndexer/PagesIndexer.php index 5c1bca47..c2464c63 100644 --- a/Classes/Domain/Index/TcaIndexer/PagesIndexer.php +++ b/Classes/Domain/Index/TcaIndexer/PagesIndexer.php @@ -26,19 +26,12 @@ use Codappix\SearchCore\Domain\Index\TcaIndexer; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Core\Utility\RootlineUtility; -use TYPO3\CMS\Extbase\Object\ObjectManager; -use TYPO3\CMS\Extbase\Object\ObjectManagerInterface; /** * Specific indexer for Pages, will basically add content of page. */ class PagesIndexer extends TcaIndexer { - /** - * @var ObjectManagerInterface - */ - protected $objectManager; - /** * @var TcaTableServiceInterface */ @@ -54,12 +47,10 @@ public function __construct( TcaTableServiceInterface $tcaTableService, TcaTableServiceInterface $contentTableService, ConnectionInterface $connection, - ConfigurationContainerInterface $configuration, - ObjectManagerInterface $objectManager + ConfigurationContainerInterface $configuration ) { parent::__construct($tcaTableService, $connection, $configuration); $this->contentTableService = $contentTableService; - $this->objectManager = $objectManager; } protected function prepareRecord(array &$record) diff --git a/Classes/Domain/Model/SearchRequest.php b/Classes/Domain/Model/SearchRequest.php index 32efb5da..29756d0e 100644 --- a/Classes/Domain/Model/SearchRequest.php +++ b/Classes/Domain/Model/SearchRequest.php @@ -24,7 +24,6 @@ use Codappix\SearchCore\Connection\ConnectionInterface; use Codappix\SearchCore\Connection\FacetRequestInterface; use Codappix\SearchCore\Connection\SearchRequestInterface; -use Codappix\SearchCore\Connection\SearchResultInterface; use Codappix\SearchCore\Domain\Search\SearchServiceInterface; use Codappix\SearchCore\Utility\ArrayUtility; From 1efb06d84b78df2844d144b8c1060d3df2cb9b5a Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Sun, 30 Dec 2018 14:01:38 +0100 Subject: [PATCH 69/73] TASK: Remove wrong phpdoc --- Classes/Domain/Model/QueryResultInterfaceStub.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/Classes/Domain/Model/QueryResultInterfaceStub.php b/Classes/Domain/Model/QueryResultInterfaceStub.php index c7af6be7..6cd6f4fe 100644 --- a/Classes/Domain/Model/QueryResultInterfaceStub.php +++ b/Classes/Domain/Model/QueryResultInterfaceStub.php @@ -45,9 +45,6 @@ public function toArray() throw new \BadMethodCallException('Method is not implemented yet.', 1502195135); } - /** - * @throws \BadMethodCallException - */ public function offsetExists($offset) { // Return false to allow Fluid to use appropriate getter methods. From a6f7f31274975dcefe2d07f9137cef896f882367 Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Sun, 30 Dec 2018 14:01:45 +0100 Subject: [PATCH 70/73] TASK: Do not publish internal method --- Classes/Domain/Index/AbstractIndexer.php | 2 +- Classes/Domain/Index/TcaIndexer.php | 2 +- .../source/changelog/0.1.0/2018-changed-interfaces.rst | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Classes/Domain/Index/AbstractIndexer.php b/Classes/Domain/Index/AbstractIndexer.php index 7eae6156..0172c12c 100644 --- a/Classes/Domain/Index/AbstractIndexer.php +++ b/Classes/Domain/Index/AbstractIndexer.php @@ -208,5 +208,5 @@ abstract protected function getRecord(int $identifier): array; abstract protected function getDocumentName(): string; - abstract public function getDocumentIdentifier($identifier): string; + abstract protected function getDocumentIdentifier($identifier): string; } diff --git a/Classes/Domain/Index/TcaIndexer.php b/Classes/Domain/Index/TcaIndexer.php index e1b03b75..0c1d00d0 100644 --- a/Classes/Domain/Index/TcaIndexer.php +++ b/Classes/Domain/Index/TcaIndexer.php @@ -89,7 +89,7 @@ protected function getDocumentName(): string return $this->tcaTableService->getTableName(); } - public function getDocumentIdentifier($identifier): string + protected function getDocumentIdentifier($identifier): string { return $this->getDocumentName() . '-' . $identifier; } diff --git a/Documentation/source/changelog/0.1.0/2018-changed-interfaces.rst b/Documentation/source/changelog/0.1.0/2018-changed-interfaces.rst index 669c7765..93d5c813 100644 --- a/Documentation/source/changelog/0.1.0/2018-changed-interfaces.rst +++ b/Documentation/source/changelog/0.1.0/2018-changed-interfaces.rst @@ -15,7 +15,7 @@ Some interfaces and abstract classes have been adjusted: ``Codappix\SearchCore\Domain\Index\AbstractIndexer``: - * New method ``abstract public function getDocumentIdentifier($identifier): string;`` + * New method ``abstract protected function getDocumentIdentifier($identifier): string;`` ``Codappix\SearchCore\Connection\SearchRequestInterface``: From 4c99009ea0aed618f776c92325ac9ea9dee04c40 Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Sun, 30 Dec 2018 14:45:16 +0100 Subject: [PATCH 71/73] TASK: Remove cache implementation As it does not use TYPO3 caching framework but custom feature. --- Classes/Domain/Search/CachedSearchService.php | 69 ------------------- .../0.1.0/2018-changed-interfaces.rst | 4 +- .../Unit/Controller/SearchControllerTest.php | 4 +- ext_localconf.php | 8 +-- 4 files changed, 7 insertions(+), 78 deletions(-) delete mode 100644 Classes/Domain/Search/CachedSearchService.php diff --git a/Classes/Domain/Search/CachedSearchService.php b/Classes/Domain/Search/CachedSearchService.php deleted file mode 100644 index a8655f3c..00000000 --- a/Classes/Domain/Search/CachedSearchService.php +++ /dev/null @@ -1,69 +0,0 @@ - - * - * 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 Codappix\SearchCore\Connection\SearchResultInterface; -use TYPO3\CMS\Core\SingletonInterface; - -/** - * Service to process a search request, only once per request. - */ -class CachedSearchService implements SingletonInterface, SearchServiceInterface -{ - /** - * @var array - */ - protected $results = []; - - /** - * @var SearchService - */ - protected $searchService; - - public function __construct(SearchService $searchService) - { - $this->searchService = $searchService; - } - - public function search(SearchRequestInterface $searchRequest): SearchResultInterface - { - $hash = $this->getHash($searchRequest); - if (isset($this->results[$hash]) && $this->results[$hash] instanceof SearchResultInterface) { - return $this->results[$hash]; - } - return $this->results[$hash] = $this->searchService->search($searchRequest); - } - - public function processResult(SearchResultInterface $searchResult): SearchResultInterface - { - return $this->searchService->processResult($searchResult); - } - - protected function getHash(SearchRequestInterface $searchRequest): string - { - if (is_callable([$searchRequest, 'getRequestHash'])) { - return (string)$searchRequest->getRequestHash(); - } - return sha1(serialize($searchRequest)); - } -} diff --git a/Documentation/source/changelog/0.1.0/2018-changed-interfaces.rst b/Documentation/source/changelog/0.1.0/2018-changed-interfaces.rst index 93d5c813..740acb35 100644 --- a/Documentation/source/changelog/0.1.0/2018-changed-interfaces.rst +++ b/Documentation/source/changelog/0.1.0/2018-changed-interfaces.rst @@ -25,8 +25,8 @@ Some interfaces and abstract classes have been adjusted: Also some exceptions have changed: * ``Codappix\SearchCore\Connection\Elasticsearch\DocumentFactory::getDocument()`` now -throws an ``\InvalidArgumentException`` instead of ``\Exception``, if no -``search_identifier`` was provided. + throws an ``\InvalidArgumentException`` instead of ``\Exception``, if no + ``search_identifier`` was provided. * ``Codappix\SearchCore\Connection\Elasticsearch\IndexFactory::getIndex()`` now throws an ``\InvalidArgumentException`` if the index does not exist. Leaving diff --git a/Tests/Unit/Controller/SearchControllerTest.php b/Tests/Unit/Controller/SearchControllerTest.php index 0357b868..6c9fed64 100644 --- a/Tests/Unit/Controller/SearchControllerTest.php +++ b/Tests/Unit/Controller/SearchControllerTest.php @@ -23,7 +23,7 @@ use Codappix\SearchCore\Controller\SearchController; use Codappix\SearchCore\Domain\Model\SearchRequest; -use Codappix\SearchCore\Domain\Search\CachedSearchService; +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; @@ -55,7 +55,7 @@ public function setUp() parent::setUp(); - $searchService = $this->getMockBuilder(CachedSearchService::class) + $searchService = $this->getMockBuilder(SearchService::class) ->disableOriginalConstructor() ->getMock(); $this->request = new Request(); diff --git a/ext_localconf.php b/ext_localconf.php index 0941be32..f400aa55 100644 --- a/ext_localconf.php +++ b/ext_localconf.php @@ -58,14 +58,12 @@ (isset($configuration['disable.']['elasticsearch']) && filter_var($configuration['disable.']['elasticsearch'], FILTER_VALIDATE_BOOLEAN) === false) ) { - $container = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\Object\Container\Container::class); + $container = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance( + \TYPO3\CMS\Extbase\Object\Container\Container::class + ); $container->registerImplementation( \Codappix\SearchCore\Connection\ConnectionInterface::class, \Codappix\SearchCore\Connection\Elasticsearch::class ); - $container->registerImplementation( - \Codappix\SearchCore\Domain\Search\SearchServiceInterface::class, - \Codappix\SearchCore\Domain\Search\CachedSearchService::class - ); } })($_EXTKEY, $_EXTCONF); From f955a9b70a8842c3808c5f92a45bc937abefdf0e Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Sun, 30 Dec 2018 14:48:17 +0100 Subject: [PATCH 72/73] FEATURE: Provide basic caching --- Classes/Domain/Model/SearchRequest.php | 14 ++++++++++++ Classes/Domain/Search/SearchService.php | 22 +++++++++++++++++-- Documentation/source/changelog/0.1.0.rst | 1 + .../changelog/0.1.0/2018-added-caching.rst | 22 +++++++++++++++++++ Documentation/source/conf.py | 1 + .../Unit/Domain/Search/SearchServiceTest.php | 12 +++++++++- ext_localconf.php | 8 +++++++ 7 files changed, 77 insertions(+), 3 deletions(-) create mode 100644 Documentation/source/changelog/0.1.0/2018-added-caching.rst diff --git a/Classes/Domain/Model/SearchRequest.php b/Classes/Domain/Model/SearchRequest.php index 29756d0e..183463e0 100644 --- a/Classes/Domain/Model/SearchRequest.php +++ b/Classes/Domain/Model/SearchRequest.php @@ -188,6 +188,20 @@ public function getOffset() return $this->offset; } + /** + * Used, e.g. by caching to determine identifier. + */ + public function __sleep() + { + return [ + 'query', + 'filter', + 'facets', + 'offset', + 'limit', + ]; + } + /** * @throws \BadMethodCallException */ diff --git a/Classes/Domain/Search/SearchService.php b/Classes/Domain/Search/SearchService.php index 43b54b8c..e5b81d58 100644 --- a/Classes/Domain/Search/SearchService.php +++ b/Classes/Domain/Search/SearchService.php @@ -30,6 +30,8 @@ use Codappix\SearchCore\Domain\Model\FacetRequest; use Codappix\SearchCore\Domain\Model\SearchResult; use Codappix\SearchCore\Utility\ArrayUtility; +use TYPO3\CMS\Core\Cache\CacheManager; +use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface; use TYPO3\CMS\Extbase\Object\ObjectManagerInterface; /** @@ -57,22 +59,30 @@ class SearchService implements SearchServiceInterface */ protected $dataProcessorService; + /** + * @var FrontendInterface + */ + protected $cache; + /** * @param ConnectionInterface $connection * @param ConfigurationContainerInterface $configuration * @param ObjectManagerInterface $objectManager * @param DataProcessorService $dataProcessorService + * @param CacheManager $cacheManager */ public function __construct( ConnectionInterface $connection, ConfigurationContainerInterface $configuration, ObjectManagerInterface $objectManager, - DataProcessorService $dataProcessorService + DataProcessorService $dataProcessorService, + CacheManager $cacheManager ) { $this->connection = $connection; $this->configuration = $configuration; $this->objectManager = $objectManager; $this->dataProcessorService = $dataProcessorService; + $this->cache = $cacheManager->getCache('search_core'); } public function search(SearchRequestInterface $searchRequest): SearchResultInterface @@ -85,7 +95,15 @@ public function search(SearchRequestInterface $searchRequest): SearchResultInter $searchRequest->setConnection($this->connection); $searchRequest->setSearchService($this); - return $this->processResult($this->connection->search($searchRequest)); + $identifier = sha1('search' . serialize($searchRequest)); + if ($this->cache->has($identifier)) { + return $this->cache->get($identifier); + } + + $result = $this->processResult($this->connection->search($searchRequest)); + $this->cache->set($identifier, $result); + + return $result; } /** diff --git a/Documentation/source/changelog/0.1.0.rst b/Documentation/source/changelog/0.1.0.rst index 3cfc4cec..bcd0cd68 100644 --- a/Documentation/source/changelog/0.1.0.rst +++ b/Documentation/source/changelog/0.1.0.rst @@ -4,6 +4,7 @@ v0.1.0 .. toctree:: :maxdepth: 1 + 0.1.0/2018-added-caching 0.1.0/2018-added-content-element-wizard 0.1.0/2018-changed-interfaces 0.1.0/2018-elasticsearch-upgrade diff --git a/Documentation/source/changelog/0.1.0/2018-added-caching.rst b/Documentation/source/changelog/0.1.0/2018-added-caching.rst new file mode 100644 index 00000000..bca0fe42 --- /dev/null +++ b/Documentation/source/changelog/0.1.0/2018-added-caching.rst @@ -0,0 +1,22 @@ +Feature "Added caching" +======================= + +Processing searches are now cacheable, the TYPO3 caching framework is used for +caching. By default the ``NullBackend`` is used to keep old behaviour, which matches +searches the best. + +Still if the same search is run multiple times during a single request, the +``TransientMemoryBackend`` is a nice option. + +Depending on search backend, one might also use a different backend for caching and +configure some TTL. + +.. note:: + + Paging is currently not supported for caching. + + Using ``NullBackend`` or ``TransientMemoryBackend`` will work, but using persistent + backends in combination with fluid pagination widget will lead to errors right + now. + +For further information, check out official :ref:`t3explained:caching` documentation. diff --git a/Documentation/source/conf.py b/Documentation/source/conf.py index c559ba33..f339f20a 100644 --- a/Documentation/source/conf.py +++ b/Documentation/source/conf.py @@ -304,6 +304,7 @@ intersphinx_mapping = { 't3tcaref': ('https://docs.typo3.org/typo3cms/TCAReference/', None), 't3tsref': ('https://docs.typo3.org/typo3cms/TyposcriptReference/', None), + 't3explained': ('https://docs.typo3.org/typo3cms/CoreApiReference/', None), } extlinks = { 'project': ('https://github.com/Codappix/search_core/projects/%s', 'Github project: '), diff --git a/Tests/Unit/Domain/Search/SearchServiceTest.php b/Tests/Unit/Domain/Search/SearchServiceTest.php index 3a6bff81..49e821d0 100644 --- a/Tests/Unit/Domain/Search/SearchServiceTest.php +++ b/Tests/Unit/Domain/Search/SearchServiceTest.php @@ -30,6 +30,8 @@ use Codappix\SearchCore\Domain\Model\SearchResult; use Codappix\SearchCore\Domain\Search\SearchService; use Codappix\SearchCore\Tests\Unit\AbstractUnitTestCase; +use TYPO3\CMS\Core\Cache\CacheManager; +use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface; use TYPO3\CMS\Extbase\Object\ObjectManagerInterface; class SearchServiceTest extends AbstractUnitTestCase @@ -68,6 +70,13 @@ public function setUp() { parent::setUp(); + $cacheMock = $this->getMockBuilder(FrontendInterface::class)->getMock(); + $cacheManagerMock = $this->getMockBuilder(CacheManager::class)->getMock(); + $cacheManagerMock->expects($this->any()) + ->method('getCache') + ->with('search_core') + ->willReturn($cacheMock); + $this->result = $this->getMockBuilder(SearchResultInterface::class) ->disableOriginalConstructor() ->getMock(); @@ -88,7 +97,8 @@ public function setUp() $this->connection, $this->configuration, $this->objectManager, - $this->dataProcessorService + $this->dataProcessorService, + $cacheManagerMock ); } diff --git a/ext_localconf.php b/ext_localconf.php index f400aa55..2934bc4e 100644 --- a/ext_localconf.php +++ b/ext_localconf.php @@ -54,6 +54,14 @@ '' ); + if (!is_array($GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['search_core'])) { + $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['search_core'] = []; + } + if (!isset($GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['search_core']['backend'])) { + $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['search_core']['backend'] = + \TYPO3\CMS\Core\Cache\Backend\NullBackend::class; + } + if (empty($configuration) || (isset($configuration['disable.']['elasticsearch']) && filter_var($configuration['disable.']['elasticsearch'], FILTER_VALIDATE_BOOLEAN) === false) From 73d61bd7d4812d4ba5a94c8356ad56656972ca77 Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Sun, 30 Dec 2018 15:03:10 +0100 Subject: [PATCH 73/73] FEATURE: Provide more information about concept --- Documentation/source/concepts.rst | 10 +++++++++- Documentation/source/features.rst | 10 ++++++++++ Documentation/source/readme.rst | 30 ++++++++++++++++++------------ 3 files changed, 37 insertions(+), 13 deletions(-) diff --git a/Documentation/source/concepts.rst b/Documentation/source/concepts.rst index f81121b5..d203f878 100644 --- a/Documentation/source/concepts.rst +++ b/Documentation/source/concepts.rst @@ -4,7 +4,8 @@ Concepts ======== The main concept is to provide a foundation where other developers can profit from, to provide -integrations into search services like Elasticsearch, Algolia, ... . +integrations into search services like Elasticsearch, Algolia, …. But also to provide +an ETL Framework. Our code contains the following concepts which should be understand: @@ -18,6 +19,9 @@ interfaces. The main purpose is to provide a stable API between TYPO3 and concre For information about implementing a new connection, take a look at :ref:`development_connection`. +These are equivalent to "Load" of ETL while "indexing", and equivalent to +"Extraction" in frontend mode. + .. _concepts_indexing: Indexing @@ -31,6 +35,8 @@ Currently :ref:`TcaIndexer` and :ref:`PagesIndexer` are provided. For information about implementing a new indexer, take a look at :ref:`development_indexer`. +This is the process of "loading" data inside the ETL. + .. _concepts_dataprocessing: DataProcessing @@ -47,3 +53,5 @@ flexible as integrators are able to configure DataProcessors and change their or Configuration is done through TypoScript, see :ref:`dataprocessors`. For information about implementing a new DataProcessor, take a look at :ref:`development_dataprocessor`. + +This is the "transforming" step of ETL. diff --git a/Documentation/source/features.rst b/Documentation/source/features.rst index 57014bdf..1cb5a660 100644 --- a/Documentation/source/features.rst +++ b/Documentation/source/features.rst @@ -46,6 +46,16 @@ output. See :ref:`concepts_dataprocessing` in :ref:`concepts` section. +.. _feature_up_to_you: + +Up to you +--------- + +The following is not provided by default, but possible with custom PHP code: + +* Integrating Social Media Feed imports via custom indexer to display feed content + inside of TYPO3 or publishing via custom connections. + .. _features_planned: Planned diff --git a/Documentation/source/readme.rst b/Documentation/source/readme.rst index f4ad9179..6f26c433 100644 --- a/Documentation/source/readme.rst +++ b/Documentation/source/readme.rst @@ -7,22 +7,28 @@ Introduction What does it do? ---------------- -The goal of this extension is to provide search integrations into TYPO3 CMS. The extension will -provide a convenient API to allow developers to provide concrete implementations of backends like -Elasticsearch, Algolia or Solr. +Contrary to most search solutions, search_core is an ETL (=Extract, Transform, Load) +Framework. This allows to extract data from one source, transform it, and load them +into an target system. Focusing on search solutions, but not limited to them. -The extension provides integration into TYPO3 like a frontend plugin for searches and hooks to -update search indexes on updates. Also a command line interface is provided for interactions like -re-indexing. +The provided process is to extract data from TYPO3 database storage using TCA, to +transform those data using data processors, and to load them into some search +storage like Elasticsearch. This is done via Hooks and CLI. + +Also the process is to extract data from some storage like Elasticsearch, transform +the data using data processors and to load them into the TYPO3 frontend. This is done +via a Frontend Plugin. Current state ------------- -This is still a very early beta version. More information can be taken from Github at -`current issues`_. +The basic necessary features are already implemented. Still features like workspaces +or multi language are not provided out of the box. -We are also focusing on Code Quality and Testing through `travis ci`_, ``phpcs``, ``phpunit`` and -``phpstan``. +Also only Elasticsearch is provided out of the box as a storage backend. But an +implementation for Algolia is already available via 3rd Party: +https://github.com/martinhummer/search_algolia -.. _current issues: https://github.com/Codappix/search_core/issues -.. _travis ci: https://travis-ci.org/Codappix/search_core +As the initial intend was to provide a common API and implementation for arbitrary +search implementations for TYPO3, the API is not fully implemented for ETL right now. +Also that's the reason for using "search_core" as extension name.