From 0a9da38357afa98cbb6961edc8b6f73ac09b8a5a Mon Sep 17 00:00:00 2001 From: Mateusz Bieniek Date: Fri, 22 Nov 2019 10:36:39 +0100 Subject: [PATCH] EZP-30951: Added missing support for searching (Not)Empty Field values (#157) * Added missing features for Empty and Null field values * Fixups after CR * fixups * Removed changes for Null Searching * Fixups after CR * CS Fixups * Fixups after CR * Small change for FieldEmpty Vistor * Changes after CR * Fixups after CR * Updated composer.json kernel requirement --- composer.json | 2 +- .../ContentDocumentEmptyFields.php | 108 ++++++++++++++++++ .../CriterionVisitor/Field/FieldEmpty.php | 93 +++++++++++++++ .../container/solr/criterion_visitors.yml | 11 ++ .../config/container/solr/field_mappers.yml | 9 ++ 5 files changed, 222 insertions(+), 1 deletion(-) create mode 100644 lib/FieldMapper/ContentTranslationFieldMapper/ContentDocumentEmptyFields.php create mode 100644 lib/Query/Common/CriterionVisitor/Field/FieldEmpty.php diff --git a/composer.json b/composer.json index 52d419748..494ecfa6c 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,7 @@ ], "require": { "php": "^7.1", - "ezsystems/ezpublish-kernel": "^7.5@dev", + "ezsystems/ezpublish-kernel": "^7.5.7@dev", "netgen/query-translator": "^1.0.2" }, "require-dev": { diff --git a/lib/FieldMapper/ContentTranslationFieldMapper/ContentDocumentEmptyFields.php b/lib/FieldMapper/ContentTranslationFieldMapper/ContentDocumentEmptyFields.php new file mode 100644 index 000000000..2e2abd24a --- /dev/null +++ b/lib/FieldMapper/ContentTranslationFieldMapper/ContentDocumentEmptyFields.php @@ -0,0 +1,108 @@ +contentTypeHandler = $contentTypeHandler; + $this->fieldNameGenerator = $fieldNameGenerator; + $this->fieldTypeRegistry = $fieldTypeRegistry; + } + + /** + * @param \eZ\Publish\SPI\Persistence\Content $content + * @param string $languageCode + * + * @return bool + */ + public function accept(Content $content, $languageCode) + { + return true; + } + + /** + * @param \eZ\Publish\SPI\Persistence\Content $content + * @param string $languageCode + * + * @return \eZ\Publish\SPI\Search\Field[] + */ + public function mapFields(Content $content, $languageCode) + { + $fields = []; + $contentType = $this->contentTypeHandler->load( + $content->versionInfo->contentInfo->contentTypeId + ); + + foreach ($content->fields as $field) { + if ($field->languageCode !== $languageCode) { + continue; + } + + foreach ($contentType->fieldDefinitions as $fieldDefinition) { + if ($fieldDefinition->isRequired) { + continue; + } + if ($fieldDefinition->id !== $field->fieldDefinitionId) { + continue; + } + + /** @var \eZ\Publish\Core\Persistence\FieldType $fieldType */ + $fieldType = $this->fieldTypeRegistry->getFieldType($fieldDefinition->fieldType); + $fields[] = new Field( + $name = $this->fieldNameGenerator->getName( + self::IS_EMPTY_NAME, + $fieldDefinition->identifier + ), + $fieldType->isEmptyValue($field->value), + new FieldType\BooleanField() + ); + } + } + + return $fields; + } +} diff --git a/lib/Query/Common/CriterionVisitor/Field/FieldEmpty.php b/lib/Query/Common/CriterionVisitor/Field/FieldEmpty.php new file mode 100644 index 000000000..f6589af32 --- /dev/null +++ b/lib/Query/Common/CriterionVisitor/Field/FieldEmpty.php @@ -0,0 +1,93 @@ +fieldNameGenerator = $fieldNameGenerator; + } + + /** + * Check if visitor is applicable to current criterion. + */ + public function canVisit(Criterion $criterion): bool + { + return $criterion instanceof Criterion\IsFieldEmpty; + } + + /** + * Map field value to a proper Solr representation. + * + * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException If no searchable fields are found for the given criterion target. + * + * @param \eZ\Publish\API\Repository\Values\Content\Query\Criterion $criterion + * @param \EzSystems\EzPlatformSolrSearchEngine\Query\CriterionVisitor $subVisitor + * + * @return string + */ + public function visit(Criterion $criterion, CriterionVisitor $subVisitor = null): string + { + $searchFields = $this->getSearchFields($criterion); + + if (empty($searchFields)) { + throw new InvalidArgumentException( + '$criterion->target', + "No searchable fields found for the given criterion target '{$criterion->target}'." + ); + } + + $criterion->value = (array)$criterion->value; + $queries = []; + + foreach ($searchFields as $name => $fieldType) { + foreach ($criterion->value as $value) { + $name = $this->fieldNameGenerator->getTypedName( + $this->fieldNameGenerator->getName( + ContentDocumentEmptyFields::IS_EMPTY_NAME, + $criterion->target + ), + new BooleanField() + ); + $queries[] = $name . ':' . (int) $value; + } + } + + return '(' . implode(' OR ', $queries) . ')'; + } +} diff --git a/lib/Resources/config/container/solr/criterion_visitors.yml b/lib/Resources/config/container/solr/criterion_visitors.yml index 32791d2b1..f46b3a992 100644 --- a/lib/Resources/config/container/solr/criterion_visitors.yml +++ b/lib/Resources/config/container/solr/criterion_visitors.yml @@ -7,6 +7,7 @@ parameters: ezpublish.search.solr.query.common.criterion_visitor.custom_field_in.class: EzSystems\EzPlatformSolrSearchEngine\Query\Common\CriterionVisitor\CustomField\CustomFieldIn ezpublish.search.solr.query.common.criterion_visitor.custom_field_range.class: EzSystems\EzPlatformSolrSearchEngine\Query\Common\CriterionVisitor\CustomField\CustomFieldRange ezpublish.search.solr.query.common.criterion_visitor.field_in.class: EzSystems\EzPlatformSolrSearchEngine\Query\Common\CriterionVisitor\Field\FieldIn + ezpublish.search.solr.query.common.criterion_visitor.field_empty.class: EzSystems\EzPlatformSolrSearchEngine\Query\Common\CriterionVisitor\Field\FieldEmpty ezpublish.search.solr.query.common.criterion_visitor.field_range.class: EzSystems\EzPlatformSolrSearchEngine\Query\Common\CriterionVisitor\Field\FieldRange ezpublish.search.solr.query.common.criterion_visitor.field_like.class: EzSystems\EzPlatformSolrSearchEngine\Query\Common\CriterionVisitor\Field\FieldLike ezpublish.search.solr.query.common.criterion_visitor.field_relation.class: EzSystems\EzPlatformSolrSearchEngine\Query\Common\CriterionVisitor\Field\FieldRelation @@ -108,6 +109,16 @@ services: - {name: ezpublish.search.solr.query.content.criterion_visitor} - {name: ezpublish.search.solr.query.location.criterion_visitor} + ezpublish.search.solr.query.common.criterion_visitor.field_empty: + class: "%ezpublish.search.solr.query.common.criterion_visitor.field_empty.class%" + arguments: + - "@ezpublish.search.common.field_name_resolver" + - "@ezpublish.search.common.field_value_mapper.aggregate" + - "@ezpublish.search.common.field_name_generator" + tags: + - {name: ezpublish.search.solr.query.content.criterion_visitor} + - {name: ezpublish.search.solr.query.location.criterion_visitor} + ezpublish.search.solr.query.common.criterion_visitor.field_range: class: "%ezpublish.search.solr.query.common.criterion_visitor.field_range.class%" arguments: diff --git a/lib/Resources/config/container/solr/field_mappers.yml b/lib/Resources/config/container/solr/field_mappers.yml index bd9ee844a..e5351a24a 100644 --- a/lib/Resources/config/container/solr/field_mappers.yml +++ b/lib/Resources/config/container/solr/field_mappers.yml @@ -72,3 +72,12 @@ services: - '@ezpublish.spi.persistence.content_handler' tags: - {name: ezpublish.search.solr.field_mapper.location} + + ezpublish.search.solr.field_mapper.content_translation.content_document_empty_fields: + class: EzSystems\EzPlatformSolrSearchEngine\FieldMapper\ContentTranslationFieldMapper\ContentDocumentEmptyFields + arguments: + - '@ezpublish.spi.persistence.content_type_handler' + - '@ezpublish.search.common.field_name_generator' + - '@ezpublish.persistence.field_type_registry' + tags: + - {name: ezpublish.search.solr.field_mapper.content_translation}