From 327b9eab20c7165092a98bbe05e93a7bd33120fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Randy=20=C4=8Cupi=C4=87?= Date: Thu, 7 Jan 2021 11:10:49 +0100 Subject: [PATCH 01/19] NGSTACK-489 Override queries to add extra fields property --- lib/API/Values/Content/Search/LocationQuery.php | 16 ++++++++++++++++ lib/API/Values/Content/Search/Query.php | 16 ++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 lib/API/Values/Content/Search/LocationQuery.php create mode 100644 lib/API/Values/Content/Search/Query.php diff --git a/lib/API/Values/Content/Search/LocationQuery.php b/lib/API/Values/Content/Search/LocationQuery.php new file mode 100644 index 00000000..7014c905 --- /dev/null +++ b/lib/API/Values/Content/Search/LocationQuery.php @@ -0,0 +1,16 @@ + Date: Thu, 7 Jan 2021 11:11:02 +0100 Subject: [PATCH 02/19] NGSTACK-489 Override search hit to add extra fields property --- lib/API/Values/Content/Search/SearchHit.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 lib/API/Values/Content/Search/SearchHit.php diff --git a/lib/API/Values/Content/Search/SearchHit.php b/lib/API/Values/Content/Search/SearchHit.php new file mode 100644 index 00000000..8fea091a --- /dev/null +++ b/lib/API/Values/Content/Search/SearchHit.php @@ -0,0 +1,15 @@ + Date: Thu, 7 Jan 2021 11:11:32 +0100 Subject: [PATCH 03/19] NGSTACK-489 Inject query to search results extractor --- lib/Core/Search/Solr/Handler.php | 49 ++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/lib/Core/Search/Solr/Handler.php b/lib/Core/Search/Solr/Handler.php index c1dcae9f..0af5696f 100644 --- a/lib/Core/Search/Solr/Handler.php +++ b/lib/Core/Search/Solr/Handler.php @@ -2,19 +2,58 @@ namespace Netgen\EzPlatformSearchExtra\Core\Search\Solr; -use eZ\Publish\API\Repository\Values\Content\Query\Criterion\LogicalAnd; -use eZ\Publish\API\Repository\Values\Content\Query\Criterion\LogicalNot; +use eZ\Publish\API\Repository\Values\Content\LocationQuery; +use eZ\Publish\API\Repository\Values\Content\Query; +use eZ\Publish\API\Repository\Values\Content\Query\Criterion; +use EzSystems\EzPlatformSolrSearchEngine\DocumentMapper; use EzSystems\EzPlatformSolrSearchEngine\Handler as BaseHandler; use eZ\Publish\Core\Base\Exceptions\NotFoundException; class Handler extends BaseHandler { + public function findContent(Query $query, array $languageFilter = array()) + { + $query = clone $query; + $query->filter = $query->filter ?: new Criterion\MatchAll(); + $query->query = $query->query ?: new Criterion\MatchAll(); + + $this->coreFilter->apply( + $query, + $languageFilter, + DocumentMapper::DOCUMENT_TYPE_IDENTIFIER_CONTENT + ); + + return $this->resultExtractor->extract( + $this->gateway->findContent($query, $languageFilter), + $query->facetBuilders, + $query + ); + } + + public function findLocations(LocationQuery $query, array $languageFilter = array()) + { + $query = clone $query; + $query->query = $query->query ?: new Criterion\MatchAll(); + + $this->coreFilter->apply( + $query, + $languageFilter, + DocumentMapper::DOCUMENT_TYPE_IDENTIFIER_LOCATION + ); + + return $this->resultExtractor->extract( + $this->gateway->findLocations($query, $languageFilter), + $query->facetBuilders, + $query + ); + } + protected function deleteAllItemsWithoutAdditionalLocation($locationId) { $query = $this->prepareQuery(); - $query->filter = new LogicalAnd([ + $query->filter = new Criterion\LogicalAnd([ $this->allItemsWithinLocation($locationId), - new LogicalNot($this->allItemsWithinLocationWithAdditionalLocation($locationId)), + new Criterion\LogicalNot($this->allItemsWithinLocationWithAdditionalLocation($locationId)), ]); $contentIds = $this->extractContentIds( @@ -30,7 +69,7 @@ protected function deleteAllItemsWithoutAdditionalLocation($locationId) protected function updateAllElementsWithAdditionalLocation($locationId) { $query = $this->prepareQuery(); - $query->filter = new LogicalAnd([ + $query->filter = new Criterion\LogicalAnd([ $this->allItemsWithinLocation($locationId), $this->allItemsWithinLocationWithAdditionalLocation($locationId), ]); From a518db9ee1b2f97a116e79604e8a29782156582e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Randy=20=C4=8Cupi=C4=87?= Date: Thu, 7 Jan 2021 11:11:54 +0100 Subject: [PATCH 04/19] NGSTACK-489 Extract extra fields from Solr document --- lib/Core/Search/Solr/ResultExtractor.php | 42 +++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/lib/Core/Search/Solr/ResultExtractor.php b/lib/Core/Search/Solr/ResultExtractor.php index 9ff759ef..4265cfd7 100644 --- a/lib/Core/Search/Solr/ResultExtractor.php +++ b/lib/Core/Search/Solr/ResultExtractor.php @@ -2,8 +2,13 @@ namespace Netgen\EzPlatformSearchExtra\Core\Search\Solr; +use eZ\Publish\API\Repository\Values\Content\Search\SearchResult; use EzSystems\EzPlatformSolrSearchEngine\ResultExtractor as BaseResultExtractor; use Netgen\EzPlatformSearchExtra\Core\Search\Solr\API\FacetBuilder\RawFacetBuilder; +use eZ\Publish\API\Repository\Values\Content\Query; +use Netgen\EzPlatformSearchExtra\API\Values\Content\Search\Query as ExtraQuery; +use Netgen\EzPlatformSearchExtra\API\Values\Content\Search\LocationQuery as ExtraLocationQuery; +use Netgen\EzPlatformSearchExtra\API\Values\Content\Search\SearchHit; /** * This DocumentMapper implementation adds support for handling RawFacetBuilders. @@ -12,10 +17,23 @@ */ abstract class ResultExtractor Extends BaseResultExtractor { - public function extract($data, array $facetBuilders = []) + public function extract($data, array $facetBuilders = [], ?Query $query = null) { $searchResult = $this->extractSearchResult($data, $facetBuilders); + foreach ($searchResult->searchHits as $key => $searchHit) { + $searchResult->searchHits[$key] = new SearchHit(get_object_vars($searchHit)); + $searchResult->searchHits[$key]->extraFields = []; + + if ($query instanceof ExtraQuery || $query instanceof ExtraLocationQuery) { + $searchResult->searchHits[$key]->extraFields = $this->extractExtraFields( + $data, + $searchResult->searchHits[$key], + $query->extraFields + ); + } + } + if (!isset($data->facets) || $data->facets->count === 0) { return $searchResult; } @@ -57,4 +75,26 @@ function ($facetBuilder) { } ); } + + /** + * @param mixed $data + * @param \Netgen\EzPlatformSearchExtra\API\Values\Content\Search\SearchHit $searchResult + * @param string[] $extraFields + */ + private function extractExtraFields($data, SearchHit $searchHit, $extraFields) + { + $extractedExtraFields = []; + foreach ($data->response->docs as $doc) { + if ($doc->document_type_id === 'content' && $doc->content_id_id == $searchHit->valueObject->id + || $doc->document_type_id === 'location' && $doc->location_id_id == $searchHit->valueObject->mainLocationId) { + foreach ($extraFields as $extraField) { + if (property_exists($doc, $extraField)) { + $extractedExtraFields[$extraField] = $doc->{$extraField}; + } + } + } + } + + return $extractedExtraFields; + } } From 61758b336405b9996cad1e8b663e3c2bc7bc93ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Randy=20=C4=8Cupi=C4=87?= Date: Thu, 7 Jan 2021 14:30:47 +0100 Subject: [PATCH 05/19] NGSTACK-489 Add missing sanity check --- lib/Core/Search/Solr/ResultExtractor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Core/Search/Solr/ResultExtractor.php b/lib/Core/Search/Solr/ResultExtractor.php index 4265cfd7..45bf3efb 100644 --- a/lib/Core/Search/Solr/ResultExtractor.php +++ b/lib/Core/Search/Solr/ResultExtractor.php @@ -25,7 +25,7 @@ public function extract($data, array $facetBuilders = [], ?Query $query = null) $searchResult->searchHits[$key] = new SearchHit(get_object_vars($searchHit)); $searchResult->searchHits[$key]->extraFields = []; - if ($query instanceof ExtraQuery || $query instanceof ExtraLocationQuery) { + if ($query instanceof ExtraQuery || $query instanceof ExtraLocationQuery && is_array($query->extraFields)) { $searchResult->searchHits[$key]->extraFields = $this->extractExtraFields( $data, $searchResult->searchHits[$key], From 64b1e9f36e373b47050eab54d60853d26a51212e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Randy=20=C4=8Cupi=C4=87?= Date: Tue, 19 Jan 2021 16:16:42 +0100 Subject: [PATCH 06/19] NGSTACK-489 Fix existing test --- .../API}/FulltextSpellcheckCriterionTest.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) rename tests/lib/{Solr => Integration/API}/FulltextSpellcheckCriterionTest.php (98%) diff --git a/tests/lib/Solr/FulltextSpellcheckCriterionTest.php b/tests/lib/Integration/API/FulltextSpellcheckCriterionTest.php similarity index 98% rename from tests/lib/Solr/FulltextSpellcheckCriterionTest.php rename to tests/lib/Integration/API/FulltextSpellcheckCriterionTest.php index 1f2025fa..7b77eb97 100644 --- a/tests/lib/Solr/FulltextSpellcheckCriterionTest.php +++ b/tests/lib/Integration/API/FulltextSpellcheckCriterionTest.php @@ -1,6 +1,6 @@ Date: Tue, 19 Jan 2021 16:22:46 +0100 Subject: [PATCH 07/19] NGSTACK-489 Exclude test from legacy testing --- phpunit-integration-legacy.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/phpunit-integration-legacy.xml b/phpunit-integration-legacy.xml index 13820761..7c76beb2 100644 --- a/phpunit-integration-legacy.xml +++ b/phpunit-integration-legacy.xml @@ -16,6 +16,7 @@ tests/lib/Integration/API/IsFieldEmptyCriterionTest.php tests/lib/Integration/API/SubdocumentFieldSortClauseTest.php tests/lib/Integration/API/SubdocumentQueryCriterionTest.php + tests/lib/Integration/API/FulltextSpellcheckCriterionTest.php tests/lib/Integration/Solr/RawFacetDomainTest.php tests/lib/Integration/Solr/RawFacetTest.php From ea57f2e4e8b4d12984c863a7878b05cce68253ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Randy=20=C4=8Cupi=C4=87?= Date: Tue, 19 Jan 2021 16:35:16 +0100 Subject: [PATCH 08/19] NGSTACK-489 Create field mapper for testing extra fields --- .../FieldMapper/TestContentFieldMapper.php | 151 ++++++++++++++++++ .../Integration/Resources/config/services.yml | 8 + 2 files changed, 159 insertions(+) create mode 100644 tests/lib/Integration/Implementation/Solr/FieldMapper/TestContentFieldMapper.php diff --git a/tests/lib/Integration/Implementation/Solr/FieldMapper/TestContentFieldMapper.php b/tests/lib/Integration/Implementation/Solr/FieldMapper/TestContentFieldMapper.php new file mode 100644 index 00000000..9832a862 --- /dev/null +++ b/tests/lib/Integration/Implementation/Solr/FieldMapper/TestContentFieldMapper.php @@ -0,0 +1,151 @@ +contentTypeHandler = $contentTypeHandler; + $this->searchHandler = $searchHandler; + } + + /** + * {@inheritdoc} + */ + public function accept(SPIContent $content) + { + $contentType = $this->contentTypeHandler->load( + $content->versionInfo->contentInfo->contentTypeId + ); + + return $contentType->identifier === self::CONTENT_TYPE_IDENTIFIER; + } + + /** + * {@inheritdoc} + */ + public function mapFields(SPIContent $content) + { + $contentType = $this->contentTypeHandler->load( + $content->versionInfo->contentInfo->contentTypeId + ); + + $commentCount = $this->getCommentCount($content); + + $prefixedName = 'prefix '.$this->extractField($content, $contentType, 'name')->value->data; + + return [ + new Field( + 'extra_prefixed_name', + $prefixedName, + new StringField() + ), + new Field( + 'extra_comment_count', + $commentCount, + new IntegerField() + ), + new Field( + 'extra_has_comments', + $commentCount > 0, + new BooleanField() + ), + ]; + } + + /** + * @param \eZ\Publish\SPI\Persistence\Content $content + * @param \eZ\Publish\SPI\Persistence\Content\Type $contentType + * @param $identifier + * + * @return \eZ\Publish\SPI\Persistence\Content\Field + */ + private function extractField(Content $content, ContentType $contentType, $identifier): ContentField + { + $fieldDefinitionId = $this->getFieldDefinitionId($contentType, $identifier); + + foreach ($content->fields as $field) { + if ($field->fieldDefinitionId === $fieldDefinitionId) { + return $field; + } + } + + throw new RuntimeException( + "Could not extract field '{$identifier}'" + ); + } + + /** + * @param \eZ\Publish\SPI\Persistence\Content\Type $contentType + * @param $identifier + * + * @return mixed + */ + private function getFieldDefinitionId(ContentType $contentType, $identifier) + { + foreach ($contentType->fieldDefinitions as $fieldDefinition) { + if ($fieldDefinition->identifier === $identifier) { + return $fieldDefinition->id; + } + } + + throw new RuntimeException( + "Could not extract field definition '{$identifier}'" + ); + } + + /** + * @param \eZ\Publish\SPI\Persistence\Content $content + * + * @return int + */ + private function getCommentCount(Content $content) + { + $criteria = [ + new Criterion\ParentLocationId($content->versionInfo->contentInfo->mainLocationId), + new Criterion\ContentTypeIdentifier(self::CHILD_CONTENT_TYPE_IDENTIFIER), + ]; + + $query = new LocationQuery(); + $query->filter = new Criterion\LogicalAnd($criteria); + $query->limit = 0; + + return $this->searchHandler->findLocations($query)->totalCount; + } +} diff --git a/tests/lib/Integration/Resources/config/services.yml b/tests/lib/Integration/Resources/config/services.yml index 8b3467ea..e9403bb7 100644 --- a/tests/lib/Integration/Resources/config/services.yml +++ b/tests/lib/Integration/Resources/config/services.yml @@ -19,3 +19,11 @@ services: class: '%ezpublish.search.solr.slot.publish_version.class%' tags: - {name: ezpublish.search.solr.slot, signal: ContentService\PublishVersionSignal} + + netgen_test.search.solr.field_mapper.content: + class: Netgen\EzPlatformSearchExtra\Tests\Integration\Implementation\Solr\FieldMapper\TestContentFieldMapper + arguments: + - '@ezpublish.spi.persistence.content_type_handler' + - '@ezpublish.spi.search.legacy' + tags: + - {name: ezpublish.search.solr.field_mapper.content} From ca0a72bac641d96195bd3fde03b3e447d123082c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Randy=20=C4=8Cupi=C4=87?= Date: Tue, 19 Jan 2021 16:35:39 +0100 Subject: [PATCH 09/19] NGSTACK-489 Create signal slot for testing extra fields --- .../Common/Slot/TestChildUpdatesParent.php | 56 +++++++++++++++++++ .../Integration/Resources/config/services.yml | 6 ++ 2 files changed, 62 insertions(+) create mode 100644 tests/lib/Integration/Implementation/Common/Slot/TestChildUpdatesParent.php diff --git a/tests/lib/Integration/Implementation/Common/Slot/TestChildUpdatesParent.php b/tests/lib/Integration/Implementation/Common/Slot/TestChildUpdatesParent.php new file mode 100644 index 00000000..cfb278a8 --- /dev/null +++ b/tests/lib/Integration/Implementation/Common/Slot/TestChildUpdatesParent.php @@ -0,0 +1,56 @@ +persistenceHandler->contentHandler(); + $content = $contentHandler->load($signal->contentId, $signal->versionNo); + $contentInfo = $content->versionInfo->contentInfo; + $contentType = $this->persistenceHandler->contentTypeHandler()->load($contentInfo->contentTypeId); + + if ($contentType->identifier !== self::CHILD_CONTENT_TYPE_IDENTIFIER) { + return; + } + + $parentLocation = $this->persistenceHandler->locationHandler()->load($contentInfo->mainLocationId); + $parentContentInfo = $contentHandler->loadContentInfo($parentLocation->contentId); + $parentContentType = $this->persistenceHandler->contentTypeHandler()->load($parentContentInfo->contentTypeId); + + if ($parentContentType->identifier !== self::PARENT_CONTENT_TYPE_IDENTIFIER) { + return; + } + + $this->searchHandler->indexContent( + $contentHandler->load($parentContentInfo->id, $parentContentInfo->currentVersionNo) + ); + } +} diff --git a/tests/lib/Integration/Resources/config/services.yml b/tests/lib/Integration/Resources/config/services.yml index e9403bb7..0dde8da4 100644 --- a/tests/lib/Integration/Resources/config/services.yml +++ b/tests/lib/Integration/Resources/config/services.yml @@ -20,6 +20,12 @@ services: tags: - {name: ezpublish.search.solr.slot, signal: ContentService\PublishVersionSignal} + netgen_test.search.solr.slot.child_updates_parent: + parent: ezpublish.search.solr.slot + class: Netgen\EzPlatformSearchExtra\Tests\Integration\Implementation\Common\Slot\TestChildUpdatesParent + tags: + - {name: ezpublish.search.solr.slot, signal: ContentService\PublishVersionSignal} + netgen_test.search.solr.field_mapper.content: class: Netgen\EzPlatformSearchExtra\Tests\Integration\Implementation\Solr\FieldMapper\TestContentFieldMapper arguments: From c9621a83d947344c56233acecc38d90b2e8b1910 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Randy=20=C4=8Cupi=C4=87?= Date: Tue, 19 Jan 2021 16:48:43 +0100 Subject: [PATCH 10/19] NGSTACK-489 Convert search hit to kernel search hit --- .../lib/Kernel/SearchServiceLocationTest.php | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/tests/lib/Kernel/SearchServiceLocationTest.php b/tests/lib/Kernel/SearchServiceLocationTest.php index 9e9abef0..391a9dc4 100644 --- a/tests/lib/Kernel/SearchServiceLocationTest.php +++ b/tests/lib/Kernel/SearchServiceLocationTest.php @@ -5,6 +5,8 @@ use eZ\Publish\API\Repository\Tests\SearchServiceLocationTest as KernelSearchServiceLocationTest; use eZ\Publish\API\Repository\Values\Content\LocationQuery; use eZ\Publish\API\Repository\Values\Content\Search\SearchResult as KernelSearchResult; +use eZ\Publish\API\Repository\Values\Content\Search\SearchHit as KernelSearchHit; +use Netgen\EzPlatformSearchExtra\API\Values\Content\Search\SearchHit; use Netgen\EzPlatformSearchExtra\API\Values\Content\Search\SearchResult; class SearchServiceLocationTest extends KernelSearchServiceLocationTest @@ -34,9 +36,16 @@ protected function assertQueryFixture(LocationQuery $query, $fixture, $closure = private function mapToKernelSearchResult(SearchResult $data) { + $kernelSearchHits = []; + + /** @var \Netgen\EzPlatformSearchExtra\API\Values\Content\Search\SearchHit $searchHit */ + foreach ($data->searchHits as $searchHit) { + $kernelSearchHits[] = $this->mapToKernelSearchHit($searchHit); + } + return new KernelSearchResult([ 'facets' => $data->facets, - 'searchHits' => $data->searchHits, + 'searchHits' => $kernelSearchHits, 'spellSuggestion' => $data->spellSuggestion, 'time' => $data->time, 'timedOut' => $data->timedOut, @@ -44,4 +53,15 @@ private function mapToKernelSearchResult(SearchResult $data) 'totalCount' => $data->totalCount, ]); } + + private function mapToKernelSearchHit(SearchHit $searchHit) + { + return new KernelSearchHit([ + 'valueObject' => $searchHit->valueObject, + 'score' => $searchHit->score, + 'index' => $searchHit->index, + 'matchedTranslation' => $searchHit->matchedTranslation, + 'highlight' => $searchHit->highlight, + ]); + } } From 31d370c8b822b396147dcfa376dcf14bddd5657b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Randy=20=C4=8Cupi=C4=87?= Date: Tue, 19 Jan 2021 17:15:17 +0100 Subject: [PATCH 11/19] NGSTACK-489 Convert search hit to kernel search hit v2 --- tests/lib/Kernel/SearchServiceTest.php | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/tests/lib/Kernel/SearchServiceTest.php b/tests/lib/Kernel/SearchServiceTest.php index 08aeb55e..bcaca3d7 100644 --- a/tests/lib/Kernel/SearchServiceTest.php +++ b/tests/lib/Kernel/SearchServiceTest.php @@ -5,6 +5,8 @@ use eZ\Publish\API\Repository\Tests\SearchServiceTest as KernelSearchServiceTest; use eZ\Publish\API\Repository\Values\Content\Query; use eZ\Publish\API\Repository\Values\Content\Search\SearchResult as KernelSearchResult; +use eZ\Publish\API\Repository\Values\Content\Search\SearchHit as KernelSearchHit; +use Netgen\EzPlatformSearchExtra\API\Values\Content\Search\SearchHit; use Netgen\EzPlatformSearchExtra\API\Values\Content\Search\SearchResult; class SearchServiceTest extends KernelSearchServiceTest @@ -32,9 +34,16 @@ protected function assertQueryFixture( private function mapToKernelSearchResult(SearchResult $data): KernelSearchResult { + $kernelSearchHits = []; + + /** @var \Netgen\EzPlatformSearchExtra\API\Values\Content\Search\SearchHit $searchHit */ + foreach ($data->searchHits as $searchHit) { + $kernelSearchHits[] = $this->mapToKernelSearchHit($searchHit); + } + return new KernelSearchResult([ 'facets' => $data->facets, - 'searchHits' => $data->searchHits, + 'searchHits' => $kernelSearchHits, 'spellSuggestion' => $data->spellSuggestion, 'time' => $data->time, 'timedOut' => $data->timedOut, @@ -42,4 +51,15 @@ private function mapToKernelSearchResult(SearchResult $data): KernelSearchResult 'totalCount' => $data->totalCount, ]); } + + private function mapToKernelSearchHit(SearchHit $searchHit): KernelSearchHit + { + return new KernelSearchHit([ + 'valueObject' => $searchHit->valueObject, + 'score' => $searchHit->score, + 'index' => $searchHit->index, + 'matchedTranslation' => $searchHit->matchedTranslation, + 'highlight' => $searchHit->highlight, + ]); + } } From a5b4d566937f6c42a27f58d52296f328a34a3dae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Randy=20=C4=8Cupi=C4=87?= Date: Wed, 20 Jan 2021 17:04:35 +0100 Subject: [PATCH 12/19] NGSTACK-489 Create test for extra fields --- phpunit-integration-legacy.xml | 1 + tests/lib/Integration/API/ExtraFieldsTest.php | 194 ++++++++++++++++++ 2 files changed, 195 insertions(+) create mode 100644 tests/lib/Integration/API/ExtraFieldsTest.php diff --git a/phpunit-integration-legacy.xml b/phpunit-integration-legacy.xml index 7c76beb2..73e99637 100644 --- a/phpunit-integration-legacy.xml +++ b/phpunit-integration-legacy.xml @@ -17,6 +17,7 @@ tests/lib/Integration/API/SubdocumentFieldSortClauseTest.php tests/lib/Integration/API/SubdocumentQueryCriterionTest.php tests/lib/Integration/API/FulltextSpellcheckCriterionTest.php + tests/lib/Integration/API/ExtraFieldsTest.php tests/lib/Integration/Solr/RawFacetDomainTest.php tests/lib/Integration/Solr/RawFacetTest.php diff --git a/tests/lib/Integration/API/ExtraFieldsTest.php b/tests/lib/Integration/API/ExtraFieldsTest.php new file mode 100644 index 00000000..c51e15dd --- /dev/null +++ b/tests/lib/Integration/API/ExtraFieldsTest.php @@ -0,0 +1,194 @@ + new FullTextCriterion('comments'), + 'filter' => new Criterion\ContentTypeIdentifier('extra_fields_test'), + 'extraFields' => [], + ]), + [], + ], + [ + new LocationQuery([ + 'query' => new FullTextCriterion('comments'), + 'filter' => new Criterion\ContentTypeIdentifier('extra_fields_test'), + 'extraFields' => ['extra_prefixed_name_s'], + ]), + [ + 'extra_prefixed_name_s' => 'prefix No comments article', + ], + ], + [ + new LocationQuery([ + 'query' => new FullTextCriterion('comments'), + 'filter' => new Criterion\ContentTypeIdentifier('extra_fields_test'), + 'extraFields' => ['extra_comment_count_i', 'extra_has_comments_b'], + ]), + [ + 'extra_comment_count_i' => 0, + 'extra_has_comments_b' => false, + ], + ], + [ + new LocationQuery([ + 'query' => new FullTextCriterion('comments'), + 'filter' => new Criterion\ContentTypeIdentifier('extra_fields_test'), + 'extraFields' => ['extra_prefixed_name_s', 'extra_comment_count_i', 'extra_has_comments_b'], + ]), + [ + 'extra_prefixed_name_s' => 'prefix No comments article', + 'extra_comment_count_i' => 0, + 'extra_has_comments_b' => false, + ], + ], + [ + new LocationQuery([ + 'query' => new FullTextCriterion('popular'), + 'filter' => new Criterion\ContentTypeIdentifier('extra_fields_test'), + 'extraFields' => ['extra_prefixed_name_s', 'extra_comment_count_i', 'extra_has_comments_b'], + ]), + [ + 'extra_prefixed_name_s' => 'prefix Very popular article', + 'extra_comment_count_i' => 6, + 'extra_has_comments_b' => true, + ], + ], + [ + new LocationQuery([ + 'query' => new FullTextCriterion('another'), + 'filter' => new Criterion\ContentTypeIdentifier('extra_fields_test'), + 'extraFields' => ['extra_prefixed_name_s', 'extra_comment_count_i', 'extra_has_comments_b'], + ]), + [ + 'extra_prefixed_name_s' => 'prefix Just another article', + 'extra_comment_count_i' => 2, + 'extra_has_comments_b' => true, + ], + ], + ]; + } + + /** + * @throws \eZ\Publish\API\Repository\Exceptions\BadStateException + * @throws \eZ\Publish\API\Repository\Exceptions\ContentFieldValidationException + * @throws \eZ\Publish\API\Repository\Exceptions\ContentTypeFieldDefinitionValidationException + * @throws \eZ\Publish\API\Repository\Exceptions\ContentValidationException + * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException + * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException + * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException + */ + public function testPrepareTestFixtures() + { + $repository = $this->getRepository(); + $contentService = $repository->getContentService(); + $contentTypeService = $repository->getContentTypeService(); + $locationService = $repository->getLocationService(); + + $contentTypeGroups = $contentTypeService->loadContentTypeGroups(); + $contentTypeCreateStruct = $contentTypeService->newContentTypeCreateStruct('extra_fields_test'); + $contentTypeCreateStruct->mainLanguageCode = 'eng-GB'; + $contentTypeCreateStruct->names = ['eng-GB' => 'Article']; + + $fieldDefinitionCreateStruct = $contentTypeService->newFieldDefinitionCreateStruct('name', 'ezstring'); + $fieldDefinitionCreateStruct->position = 0; + $contentTypeCreateStruct->addFieldDefinition($fieldDefinitionCreateStruct); + + $contentTypeDraft = $contentTypeService->createContentType($contentTypeCreateStruct, [reset($contentTypeGroups)]); + $contentTypeService->publishContentTypeDraft($contentTypeDraft); + $contentType = $contentTypeService->loadContentTypeByIdentifier('extra_fields_test'); + + $contentTypeCreateStruct = $contentTypeService->newContentTypeCreateStruct('extra_fields_test_comment'); + $contentTypeCreateStruct->mainLanguageCode = 'eng-GB'; + $contentTypeCreateStruct->names = ['eng-GB' => 'Comment']; + + $fieldDefinitionCreateStruct = $contentTypeService->newFieldDefinitionCreateStruct('comment', 'ezstring'); + $fieldDefinitionCreateStruct->position = 0; + $contentTypeCreateStruct->addFieldDefinition($fieldDefinitionCreateStruct); + + $contentTypeDraft = $contentTypeService->createContentType($contentTypeCreateStruct, [reset($contentTypeGroups)]); + $contentTypeService->publishContentTypeDraft($contentTypeDraft); + $commentContentType = $contentTypeService->loadContentTypeByIdentifier('extra_fields_test_comment'); + + $values = [ + 'No comments article' => [], + 'Very popular article' => ['comment 1', 'another comment', 'test comment', 'comment on comment', 'comment 2', 'test'], + 'Just another article' => ['first comment', 'second comment'], + ]; + + $locationCreateStruct = $locationService->newLocationCreateStruct(2); + + foreach ($values as $title => $comments) { + $contentCreateStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB'); + $contentCreateStruct->setField('name', $title); + $contentDraft = $contentService->createContent($contentCreateStruct, [$locationCreateStruct]); + $articleContent = $contentService->publishVersion($contentDraft->versionInfo); + + foreach ($comments as $comment) { + $commentLocationCreateStruct = $locationService->newLocationCreateStruct($articleContent->contentInfo->mainLocationId); + $commentContentCreateStruct = $contentService->newContentCreateStruct($commentContentType, 'eng-GB'); + $commentContentCreateStruct->setField('comment', $comment); + $commentContentDraft = $contentService->createContent($commentContentCreateStruct, [$commentLocationCreateStruct]); + $contentService->publishVersion($commentContentDraft->versionInfo); + } + } + + $this->refreshSearch($repository); + + $this->assertTrue(true); + } + + /** + * @dataProvider providerForTestFind + * + * @param \eZ\Publish\API\Repository\Values\Content\Query $query + * @param array $expectedExtraFields + * + * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException + */ + public function testFindContent(Query $query, array $expectedExtraFields) + { + $searchService = $this->getSearchService(false); + + /** @var \Netgen\EzPlatformSearchExtra\API\Values\Content\Search\SearchResult $searchResult */ + $searchResult = $searchService->findContentInfo($query); + + $this->assertEquals($expectedExtraFields, $searchResult->searchHits[0]->extraFields); + } + + /** + * @dataProvider providerForTestFind + * + * @param \Netgen\EzPlatformSearchExtra\API\Values\Content\Search\LocationQuery $query + * @param array $expectedExtraFields + */ + public function testFindLocations(LocationQuery $query, array $expectedExtraFields) + { + $searchService = $this->getSearchService(false); + + /** @var \Netgen\EzPlatformSearchExtra\API\Values\Content\Search\SearchResult $searchResult */ + $searchResult = $searchService->findLocations($query); + + $this->assertEquals($expectedExtraFields, $searchResult->searchHits[0]->extraFields); + } + + protected function getSearchService($initialInitializeFromScratch = true) + { + return $this->getRepository($initialInitializeFromScratch)->getSearchService(); + } +} From 9aea3ccbae9cb4f2fece8468417245350f4a822e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Randy=20=C4=8Cupi=C4=87?= Date: Thu, 21 Jan 2021 15:55:45 +0100 Subject: [PATCH 13/19] NGSTACK-489 Fix result extractor to support SPI content/location --- lib/Core/Search/Solr/ResultExtractor.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/Core/Search/Solr/ResultExtractor.php b/lib/Core/Search/Solr/ResultExtractor.php index 45bf3efb..4edea0f7 100644 --- a/lib/Core/Search/Solr/ResultExtractor.php +++ b/lib/Core/Search/Solr/ResultExtractor.php @@ -2,7 +2,6 @@ namespace Netgen\EzPlatformSearchExtra\Core\Search\Solr; -use eZ\Publish\API\Repository\Values\Content\Search\SearchResult; use EzSystems\EzPlatformSolrSearchEngine\ResultExtractor as BaseResultExtractor; use Netgen\EzPlatformSearchExtra\Core\Search\Solr\API\FacetBuilder\RawFacetBuilder; use eZ\Publish\API\Repository\Values\Content\Query; @@ -78,15 +77,17 @@ function ($facetBuilder) { /** * @param mixed $data - * @param \Netgen\EzPlatformSearchExtra\API\Values\Content\Search\SearchHit $searchResult + * @param \Netgen\EzPlatformSearchExtra\API\Values\Content\Search\SearchHit $searchHit * @param string[] $extraFields + * + * @return array */ private function extractExtraFields($data, SearchHit $searchHit, $extraFields) { $extractedExtraFields = []; foreach ($data->response->docs as $doc) { if ($doc->document_type_id === 'content' && $doc->content_id_id == $searchHit->valueObject->id - || $doc->document_type_id === 'location' && $doc->location_id_id == $searchHit->valueObject->mainLocationId) { + || $doc->document_type_id === 'location' && $doc->location_id == $searchHit->valueObject->id) { foreach ($extraFields as $extraField) { if (property_exists($doc, $extraField)) { $extractedExtraFields[$extraField] = $doc->{$extraField}; From c8cee7630136b8b3c678d24f7dc59a9f6fe53a56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Randy=20=C4=8Cupi=C4=87?= Date: Thu, 21 Jan 2021 15:56:21 +0100 Subject: [PATCH 14/19] NGSTACK-489 Implement content and location field mapper --- .../FieldMapper/TestContentFieldMapper.php | 133 +-------------- .../FieldMapper/TestFieldMapperInterface.php | 10 ++ .../Solr/FieldMapper/TestFieldMapperTrait.php | 156 ++++++++++++++++++ .../FieldMapper/TestLocationFieldMapper.php | 35 ++++ .../Integration/Resources/config/services.yml | 10 ++ 5 files changed, 216 insertions(+), 128 deletions(-) create mode 100644 tests/lib/Integration/Implementation/Solr/FieldMapper/TestFieldMapperInterface.php create mode 100644 tests/lib/Integration/Implementation/Solr/FieldMapper/TestFieldMapperTrait.php create mode 100644 tests/lib/Integration/Implementation/Solr/FieldMapper/TestLocationFieldMapper.php diff --git a/tests/lib/Integration/Implementation/Solr/FieldMapper/TestContentFieldMapper.php b/tests/lib/Integration/Implementation/Solr/FieldMapper/TestContentFieldMapper.php index 9832a862..be834990 100644 --- a/tests/lib/Integration/Implementation/Solr/FieldMapper/TestContentFieldMapper.php +++ b/tests/lib/Integration/Implementation/Solr/FieldMapper/TestContentFieldMapper.php @@ -2,150 +2,27 @@ namespace Netgen\EzPlatformSearchExtra\Tests\Integration\Implementation\Solr\FieldMapper; -use eZ\Publish\API\Repository\Values\Content\LocationQuery; -use eZ\Publish\SPI\Persistence\Content; use eZ\Publish\SPI\Persistence\Content as SPIContent; -use eZ\Publish\SPI\Persistence\Content\Field as ContentField; -use eZ\Publish\SPI\Persistence\Content\Type as ContentType; -use eZ\Publish\SPI\Persistence\Content\Type\Handler as ContentTypeHandler; -use eZ\Publish\SPI\Search\Field; -use eZ\Publish\SPI\Search\FieldType\BooleanField; -use eZ\Publish\SPI\Search\FieldType\IntegerField; -use eZ\Publish\SPI\Search\FieldType\StringField; -use eZ\Publish\SPI\Search\Handler as SearchHandler; use EzSystems\EzPlatformSolrSearchEngine\FieldMapper\ContentFieldMapper; -use eZ\Publish\API\Repository\Values\Content\Query\Criterion; -use RuntimeException; -class TestContentFieldMapper extends ContentFieldMapper +class TestContentFieldMapper extends ContentFieldMapper implements TestFieldMapperInterface { - const CONTENT_TYPE_IDENTIFIER = 'extra_fields_test'; - - const CHILD_CONTENT_TYPE_IDENTIFIER = 'extra_fields_test_comment'; - - /** - * @var \eZ\Publish\SPI\Persistence\Content\Type\Handler - */ - private $contentTypeHandler; - - /** - * @var \eZ\Publish\SPI\Search\Handler - */ - private $searchHandler; - - /** - * TestContentFieldMapper constructor. - * - * @param \eZ\Publish\SPI\Persistence\Content\Type\Handler $contentTypeHandler - * @param \eZ\Publish\SPI\Search\Handler $searchHandler - */ - public function __construct(ContentTypeHandler $contentTypeHandler, SearchHandler $searchHandler) - { - $this->contentTypeHandler = $contentTypeHandler; - $this->searchHandler = $searchHandler; - } + use TestFieldMapperTrait; /** * {@inheritdoc} */ public function accept(SPIContent $content) { - $contentType = $this->contentTypeHandler->load( - $content->versionInfo->contentInfo->contentTypeId - ); - - return $contentType->identifier === self::CONTENT_TYPE_IDENTIFIER; + return $this->accepts($content); } + /** * {@inheritdoc} */ public function mapFields(SPIContent $content) { - $contentType = $this->contentTypeHandler->load( - $content->versionInfo->contentInfo->contentTypeId - ); - - $commentCount = $this->getCommentCount($content); - - $prefixedName = 'prefix '.$this->extractField($content, $contentType, 'name')->value->data; - - return [ - new Field( - 'extra_prefixed_name', - $prefixedName, - new StringField() - ), - new Field( - 'extra_comment_count', - $commentCount, - new IntegerField() - ), - new Field( - 'extra_has_comments', - $commentCount > 0, - new BooleanField() - ), - ]; - } - - /** - * @param \eZ\Publish\SPI\Persistence\Content $content - * @param \eZ\Publish\SPI\Persistence\Content\Type $contentType - * @param $identifier - * - * @return \eZ\Publish\SPI\Persistence\Content\Field - */ - private function extractField(Content $content, ContentType $contentType, $identifier): ContentField - { - $fieldDefinitionId = $this->getFieldDefinitionId($contentType, $identifier); - - foreach ($content->fields as $field) { - if ($field->fieldDefinitionId === $fieldDefinitionId) { - return $field; - } - } - - throw new RuntimeException( - "Could not extract field '{$identifier}'" - ); - } - - /** - * @param \eZ\Publish\SPI\Persistence\Content\Type $contentType - * @param $identifier - * - * @return mixed - */ - private function getFieldDefinitionId(ContentType $contentType, $identifier) - { - foreach ($contentType->fieldDefinitions as $fieldDefinition) { - if ($fieldDefinition->identifier === $identifier) { - return $fieldDefinition->id; - } - } - - throw new RuntimeException( - "Could not extract field definition '{$identifier}'" - ); - } - - /** - * @param \eZ\Publish\SPI\Persistence\Content $content - * - * @return int - */ - private function getCommentCount(Content $content) - { - $criteria = [ - new Criterion\ParentLocationId($content->versionInfo->contentInfo->mainLocationId), - new Criterion\ContentTypeIdentifier(self::CHILD_CONTENT_TYPE_IDENTIFIER), - ]; - - $query = new LocationQuery(); - $query->filter = new Criterion\LogicalAnd($criteria); - $query->limit = 0; - - return $this->searchHandler->findLocations($query)->totalCount; + return $this->getFields($content); } } diff --git a/tests/lib/Integration/Implementation/Solr/FieldMapper/TestFieldMapperInterface.php b/tests/lib/Integration/Implementation/Solr/FieldMapper/TestFieldMapperInterface.php new file mode 100644 index 00000000..97cc23de --- /dev/null +++ b/tests/lib/Integration/Implementation/Solr/FieldMapper/TestFieldMapperInterface.php @@ -0,0 +1,10 @@ +contentHandler = $contentHandler; + $this->contentTypeHandler = $contentTypeHandler; + $this->searchHandler = $searchHandler; + } + + public function accepts(SPIContent $content) + { + $contentType = $this->contentTypeHandler->load( + $content->versionInfo->contentInfo->contentTypeId + ); + + return $contentType->identifier === self::CONTENT_TYPE_IDENTIFIER; + } + + public function getFields(SPIContent $content) + { + $contentType = $this->contentTypeHandler->load( + $content->versionInfo->contentInfo->contentTypeId + ); + + $commentCount = $this->getCommentCount($content); + + $prefixedName = 'prefix '.$this->extractField($content, $contentType, 'name')->value->data; + + return [ + new Field( + 'extra_prefixed_name', + $prefixedName, + new StringField() + ), + new Field( + 'extra_comment_count', + $commentCount, + new IntegerField() + ), + new Field( + 'extra_has_comments', + $commentCount > 0, + new BooleanField() + ), + new Field( + 'extra_content_type_identifier', + $contentType->identifier, + new StringField() + ), + ]; + } + + /** + * @param \eZ\Publish\SPI\Persistence\Content $content + * @param \eZ\Publish\SPI\Persistence\Content\Type $contentType + * @param $identifier + * + * @return \eZ\Publish\SPI\Persistence\Content\Field + */ + private function extractField(Content $content, ContentType $contentType, $identifier) + { + $fieldDefinitionId = $this->getFieldDefinitionId($contentType, $identifier); + + foreach ($content->fields as $field) { + if ($field->fieldDefinitionId === $fieldDefinitionId) { + return $field; + } + } + + throw new RuntimeException( + "Could not extract field '{$identifier}'" + ); + } + + /** + * @param \eZ\Publish\SPI\Persistence\Content\Type $contentType + * @param $identifier + * + * @return mixed + */ + private function getFieldDefinitionId(ContentType $contentType, $identifier) + { + foreach ($contentType->fieldDefinitions as $fieldDefinition) { + if ($fieldDefinition->identifier === $identifier) { + return $fieldDefinition->id; + } + } + + throw new RuntimeException( + "Could not extract field definition '{$identifier}'" + ); + } + + /** + * @param \eZ\Publish\SPI\Persistence\Content $content + * + * @return int + */ + private function getCommentCount(Content $content) + { + $criteria = [ + new Criterion\ParentLocationId($content->versionInfo->contentInfo->mainLocationId), + new Criterion\ContentTypeIdentifier(self::CHILD_CONTENT_TYPE_IDENTIFIER), + ]; + + $query = new LocationQuery(); + $query->filter = new Criterion\LogicalAnd($criteria); + $query->limit = 0; + + return $this->searchHandler->findLocations($query)->totalCount; + } +} diff --git a/tests/lib/Integration/Implementation/Solr/FieldMapper/TestLocationFieldMapper.php b/tests/lib/Integration/Implementation/Solr/FieldMapper/TestLocationFieldMapper.php new file mode 100644 index 00000000..49ce69bc --- /dev/null +++ b/tests/lib/Integration/Implementation/Solr/FieldMapper/TestLocationFieldMapper.php @@ -0,0 +1,35 @@ +contentHandler->load($location->contentId); + + return $this->accepts($content); + } + + /** + * @param \eZ\Publish\SPI\Persistence\Content\Location $location + * + * @return \eZ\Publish\SPI\Search\Field[]|void + */ + public function mapFields(SPILocation $location) + { + $content = $this->contentHandler->load($location->contentId); + + return $this->getFields($content); + } +} diff --git a/tests/lib/Integration/Resources/config/services.yml b/tests/lib/Integration/Resources/config/services.yml index 0dde8da4..5651d4b2 100644 --- a/tests/lib/Integration/Resources/config/services.yml +++ b/tests/lib/Integration/Resources/config/services.yml @@ -29,7 +29,17 @@ services: netgen_test.search.solr.field_mapper.content: class: Netgen\EzPlatformSearchExtra\Tests\Integration\Implementation\Solr\FieldMapper\TestContentFieldMapper arguments: + - '@ezpublish.spi.persistence.content_handler' - '@ezpublish.spi.persistence.content_type_handler' - '@ezpublish.spi.search.legacy' tags: - {name: ezpublish.search.solr.field_mapper.content} + + netgen_test.search.solr.field_mapper.location: + class: Netgen\EzPlatformSearchExtra\Tests\Integration\Implementation\Solr\FieldMapper\TestLocationFieldMapper + arguments: + - '@ezpublish.spi.persistence.content_handler' + - '@ezpublish.spi.persistence.content_type_handler' + - '@ezpublish.spi.search.legacy' + tags: + - { name: ezpublish.search.solr.field_mapper.location } From eb26720e84cc3e204cb04ef7425b0686107723e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Randy=20=C4=8Cupi=C4=87?= Date: Thu, 21 Jan 2021 15:56:31 +0100 Subject: [PATCH 15/19] NGSTACK-489 Fix signal slot --- .../Implementation/Common/Slot/TestChildUpdatesParent.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/lib/Integration/Implementation/Common/Slot/TestChildUpdatesParent.php b/tests/lib/Integration/Implementation/Common/Slot/TestChildUpdatesParent.php index cfb278a8..1d8500c3 100644 --- a/tests/lib/Integration/Implementation/Common/Slot/TestChildUpdatesParent.php +++ b/tests/lib/Integration/Implementation/Common/Slot/TestChildUpdatesParent.php @@ -41,7 +41,8 @@ public function receive(Signal $signal) return; } - $parentLocation = $this->persistenceHandler->locationHandler()->load($contentInfo->mainLocationId); + $location = $this->persistenceHandler->locationHandler()->load($contentInfo->mainLocationId); + $parentLocation = $this->persistenceHandler->locationHandler()->load($location->parentId); $parentContentInfo = $contentHandler->loadContentInfo($parentLocation->contentId); $parentContentType = $this->persistenceHandler->contentTypeHandler()->load($parentContentInfo->contentTypeId); From 0e8c09ef30b6b3ec803d69d2128396a35b145f5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Randy=20=C4=8Cupi=C4=87?= Date: Thu, 21 Jan 2021 15:56:55 +0100 Subject: [PATCH 16/19] NGSTACK-489 Improve test --- tests/lib/Integration/API/ExtraFieldsTest.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tests/lib/Integration/API/ExtraFieldsTest.php b/tests/lib/Integration/API/ExtraFieldsTest.php index c51e15dd..e8920165 100644 --- a/tests/lib/Integration/API/ExtraFieldsTest.php +++ b/tests/lib/Integration/API/ExtraFieldsTest.php @@ -18,7 +18,7 @@ public function providerForTestFind() return [ [ new LocationQuery([ - 'query' => new FullTextCriterion('comments'), + 'query' => new FullTextCriterion('*comments*'), 'filter' => new Criterion\ContentTypeIdentifier('extra_fields_test'), 'extraFields' => [], ]), @@ -28,10 +28,11 @@ public function providerForTestFind() new LocationQuery([ 'query' => new FullTextCriterion('comments'), 'filter' => new Criterion\ContentTypeIdentifier('extra_fields_test'), - 'extraFields' => ['extra_prefixed_name_s'], + 'extraFields' => ['extra_prefixed_name_s', 'extra_content_type_identifier_s'], ]), [ 'extra_prefixed_name_s' => 'prefix No comments article', + 'extra_content_type_identifier_s' => 'extra_fields_test', ], ], [ @@ -73,12 +74,13 @@ public function providerForTestFind() new LocationQuery([ 'query' => new FullTextCriterion('another'), 'filter' => new Criterion\ContentTypeIdentifier('extra_fields_test'), - 'extraFields' => ['extra_prefixed_name_s', 'extra_comment_count_i', 'extra_has_comments_b'], + 'extraFields' => ['extra_prefixed_name_s', 'extra_comment_count_i', 'extra_has_comments_b', 'extra_content_type_identifier_s'], ]), [ 'extra_prefixed_name_s' => 'prefix Just another article', 'extra_comment_count_i' => 2, 'extra_has_comments_b' => true, + 'extra_content_type_identifier_s' => 'extra_fields_test', ], ], ]; @@ -176,6 +178,8 @@ public function testFindContent(Query $query, array $expectedExtraFields) * * @param \Netgen\EzPlatformSearchExtra\API\Values\Content\Search\LocationQuery $query * @param array $expectedExtraFields + * + * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException */ public function testFindLocations(LocationQuery $query, array $expectedExtraFields) { From a736956d5a6f24ace4f44103a143b3eb3d7950d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Randy=20=C4=8Cupi=C4=87?= Date: Fri, 22 Jan 2021 08:52:53 +0100 Subject: [PATCH 17/19] NGSTACK-489 Write documentation --- docs/reference/extra_fields.rst | 56 +++++++++++++++++++++++++++++++++ docs/reference/index.rst | 1 + 2 files changed, 57 insertions(+) create mode 100644 docs/reference/extra_fields.rst diff --git a/docs/reference/extra_fields.rst b/docs/reference/extra_fields.rst new file mode 100644 index 00000000..5d1be12c --- /dev/null +++ b/docs/reference/extra_fields.rst @@ -0,0 +1,56 @@ +Extra fields from Solr +====================== + +This feature allows you to extract additionally indexed Solr fields from each SearchHit in SearchResult. For example, you can index some fields from children content on the parent content and then get those fields during search (eg. children count). + +.. note:: + + This feature is available only with the Solr search engine. + +1. Usage +~~~~~~~~ + +In order for this functionality to work, you have to use overridden `Netgen\EzPlatformSearchExtra\API\Values\Content\Search\Query` or `Netgen\EzPlatformSearchExtra\API\Values\Content\Search\LocationQuery` queries and use it's property `extraFields` provide a list of additional fields that you want to extract from the Solr document. Those fields, if exist, and their values will appear in the `extraFields` property of each `SearchHit` object contained in the `SearchResult.` + +2. Example +~~~~~~~~~~ + +Example of a content field mapper: + +.. code-block:: php + + public function mapFields(SPIContent $content) + { + return [ + new Field( + 'extra_field_example', + 5, + new IntegerField() + ), + ]; + } + +Search example: + +.. code-block:: php + + /** @var \Netgen\EzPlatformSearchExtra\API\Values\Content\Search\Query $query **/ + $query = new Query(); + + $query->extraFields = [ + 'extra_field_example_i', + ]; + + /** @var \Netgen\EzPlatformSiteApi\API\FindService $findService **/ + $searchResult = $findService->findContent($query); + + /** @var \Netgen\EzPlatformSearchExtra\API\Values\Content\Search\SearchHit $searchHit **/ + foreach ($searchResult->searchHits as $searchHit) { + var_dump($searchHit->extraFields); + } + +This will output the following data: + +.. code-block:: shell + + array(1) { ["extra_field_example_i"]=> int(5) } diff --git a/docs/reference/index.rst b/docs/reference/index.rst index 19b1ed72..1df5e41b 100644 --- a/docs/reference/index.rst +++ b/docs/reference/index.rst @@ -9,5 +9,6 @@ Reference random_sort subdocuments spellcheck_suggestions + extra_fields .. include:: /reference/map.rst.inc From 24cfb1ce1450e74ea62c663b462e72b23045ceb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Randy=20=C4=8Cupi=C4=87?= Date: Tue, 23 Feb 2021 11:53:12 +0100 Subject: [PATCH 18/19] NGSTACK-489 Fix condition --- lib/Core/Search/Solr/ResultExtractor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Core/Search/Solr/ResultExtractor.php b/lib/Core/Search/Solr/ResultExtractor.php index 4edea0f7..e66c6c6b 100644 --- a/lib/Core/Search/Solr/ResultExtractor.php +++ b/lib/Core/Search/Solr/ResultExtractor.php @@ -24,7 +24,7 @@ public function extract($data, array $facetBuilders = [], ?Query $query = null) $searchResult->searchHits[$key] = new SearchHit(get_object_vars($searchHit)); $searchResult->searchHits[$key]->extraFields = []; - if ($query instanceof ExtraQuery || $query instanceof ExtraLocationQuery && is_array($query->extraFields)) { + if (($query instanceof ExtraQuery || $query instanceof ExtraLocationQuery) && is_array($query->extraFields)) { $searchResult->searchHits[$key]->extraFields = $this->extractExtraFields( $data, $searchResult->searchHits[$key], From dae56dd3ac75ab0e9acdc4bda9dbe7f16a2418ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Randy=20=C4=8Cupi=C4=87?= Date: Tue, 23 Feb 2021 11:53:53 +0100 Subject: [PATCH 19/19] NGSTACK-489 Fix documentation --- docs/reference/extra_fields.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/extra_fields.rst b/docs/reference/extra_fields.rst index 5d1be12c..dbe2eff0 100644 --- a/docs/reference/extra_fields.rst +++ b/docs/reference/extra_fields.rst @@ -10,7 +10,7 @@ This feature allows you to extract additionally indexed Solr fields from each Se 1. Usage ~~~~~~~~ -In order for this functionality to work, you have to use overridden `Netgen\EzPlatformSearchExtra\API\Values\Content\Search\Query` or `Netgen\EzPlatformSearchExtra\API\Values\Content\Search\LocationQuery` queries and use it's property `extraFields` provide a list of additional fields that you want to extract from the Solr document. Those fields, if exist, and their values will appear in the `extraFields` property of each `SearchHit` object contained in the `SearchResult.` +In order for this functionality to work, you have to use overridden `Netgen\EzPlatformSearchExtra\API\Values\Content\Search\Query` or `Netgen\EzPlatformSearchExtra\API\Values\Content\Search\LocationQuery` queries and use it's property `extraFields` to provide a list of additional fields that you want to extract from the Solr document. Those fields, if exist, and their values will appear in the `extraFields` property of each `SearchHit` object contained in the `SearchResult.` 2. Example ~~~~~~~~~~