diff --git a/src/ElasticSearch/Config/BaseConfiguration.php b/src/ElasticSearch/Config/BaseConfiguration.php index 73e561c182aa0095786c64ae58987c690b01c4be..421dc12b6b55a04a5460c928bcb50309faebf78f 100644 --- a/src/ElasticSearch/Config/BaseConfiguration.php +++ b/src/ElasticSearch/Config/BaseConfiguration.php @@ -3,17 +3,23 @@ namespace IQDEV\ElasticSearch\Config; use IQDEV\ElasticSearch\Configuration; +use IQDEV\ElasticSearch\Mapping; class BaseConfiguration implements Configuration { + public function __construct( + private readonly Mapping $mapping, + ) { + } + public function getIndexName(): string { return $_ENV['IQ_ES_PRODUCT_SEARCH_INDEX']; } - public function getMapping(): array + public function getMapping(): Mapping { - return include __DIR__.'/product.mappings.php'; + return $this->mapping; } public function getSettings(): array diff --git a/src/ElasticSearch/Config/Mapping/ProductMapping.php b/src/ElasticSearch/Config/Mapping/ProductMapping.php new file mode 100644 index 0000000000000000000000000000000000000000..01e5d287338804f7b0f66571f0b1601bdd0419e2 --- /dev/null +++ b/src/ElasticSearch/Config/Mapping/ProductMapping.php @@ -0,0 +1,41 @@ + [ + 'type' => 'object', + 'enabled' => false, + ], + 'full_search_content' => [ + 'type' => 'text', + ], + 'suggest_search_content' => [ + 'type' => 'text', + 'analyzer' => 'autocomplete', + 'search_analyzer' => 'standard', + ], + 'category_id' => [ + 'type' => 'keyword', + 'index' => false, + ], + 'rating' => [ + 'type' => 'double', + 'index' => false, + ], + 'popular' => [ + 'type' => 'double', + 'index' => false, + ], + ]; + } +} diff --git a/src/ElasticSearch/Config/MappingValidator.php b/src/ElasticSearch/Config/MappingValidator.php index e8d6b308b9385047f3b490b467b2b144390b00f4..81faf5ed8ab1242a01ce86627064c2eb5a68c35f 100644 --- a/src/ElasticSearch/Config/MappingValidator.php +++ b/src/ElasticSearch/Config/MappingValidator.php @@ -16,7 +16,7 @@ class MappingValidator */ public static function isPropertyExists(Configuration $configuration, string $property): bool { - $properties = array_keys($configuration->getMapping()['properties'] ?? []); + $properties = array_keys($configuration->getMapping()->es()['properties'] ?? []); return in_array($property, $properties, true); } diff --git a/src/ElasticSearch/Configuration.php b/src/ElasticSearch/Configuration.php index da7c7d2a80b39e0acd3b0f5a00a0f404a8fe437c..0baecb94b078b06f14452da3f9f5a915b2b876d4 100644 --- a/src/ElasticSearch/Configuration.php +++ b/src/ElasticSearch/Configuration.php @@ -6,7 +6,7 @@ interface Configuration { public function getIndexName(): string; - public function getMapping(): array; + public function getMapping(): Mapping; public function getSettings(): array; } diff --git a/src/ElasticSearch/Converter/CriteriaToEsRequest.php b/src/ElasticSearch/Converter/CriteriaToEsRequest.php index 1bbb82bbe446905521d95000e9aad149244d70bc..333babfc646a7662f049628c0e1d819f171bc95f 100644 --- a/src/ElasticSearch/Converter/CriteriaToEsRequest.php +++ b/src/ElasticSearch/Converter/CriteriaToEsRequest.php @@ -2,29 +2,30 @@ namespace IQDEV\ElasticSearch\Converter; +use IQDEV\ElasticSearch\Config\MappingValidator; +use IQDEV\ElasticSearch\Configuration; use IQDEV\ElasticSearch\Criteria; -use IQDEV\ElasticSearch\Document\Property\AttrType; use IQDEV\ElasticSearch\Document\Property\PropertyType; -use IQDEV\ElasticSearch\Filter\Collection\FilterCollection; -use IQDEV\ElasticSearch\Filter\Collection\FilterGroupCollection; -use IQDEV\ElasticSearch\Filter\Collection\PostFilterCollection; -use IQDEV\ElasticSearch\Filter\Collection\QueryFilterCollection; -use IQDEV\ElasticSearch\Filter\Filter; -use IQDEV\ElasticSearch\Filter\FilterOperator; -use IQDEV\ElasticSearch\Filter\FilterType; -use IQDEV\ElasticSearch\Filter\LogicOperator; -use IQDEV\ElasticSearch\Filter\Value\FilterKeyword; -use IQDEV\ElasticSearch\Filter\Value\FilterNumber; -use IQDEV\ElasticSearch\Order\Order; -use IQDEV\ElasticSearch\Order\OrderField; -use IQDEV\ElasticSearch\Order\OrderKeywordProperty; -use IQDEV\ElasticSearch\Order\OrderNumberProperty; +use IQDEV\ElasticSearch\Request\Filter\Collection\FilterCollection; +use IQDEV\ElasticSearch\Request\Filter\Collection\FilterGroupCollection; +use IQDEV\ElasticSearch\Request\Filter\Collection\PostFilterCollection; +use IQDEV\ElasticSearch\Request\Filter\Collection\QueryFilterCollection; +use IQDEV\ElasticSearch\Request\Filter\Filter; +use IQDEV\ElasticSearch\Request\Filter\FilterOperator; +use IQDEV\ElasticSearch\Request\Filter\FilterType; +use IQDEV\ElasticSearch\Request\Filter\LogicOperator; +use IQDEV\ElasticSearch\Request\Filter\Value\FilterKeyword; +use IQDEV\ElasticSearch\Request\Filter\Value\FilterNumber; +use IQDEV\ElasticSearch\Request\Order\Order; +use IQDEV\ElasticSearch\Request\Search\Search; +use IQDEV\ElasticSearch\Request\Search\SearchQuery; use IQDEV\ElasticSearch\Search\Aggs\Aggs; use IQDEV\ElasticSearch\Search\Aggs\AggsFacetStats; use IQDEV\ElasticSearch\Search\Aggs\AggsFacetTerms; use IQDEV\ElasticSearch\Search\BoolQuery\FilterKeywordFacet; use IQDEV\ElasticSearch\Search\BoolQuery\FilterNumberFacet; use IQDEV\ElasticSearch\Search\BoolQuery\Query; +use IQDEV\ElasticSearch\Search\BoolQuery\Stats; use IQDEV\ElasticSearch\Search\BoolQuery\Terms; use IQDEV\ElasticSearch\Search\Nested; use IQDEV\ElasticSearch\Search\Pagination; @@ -32,11 +33,18 @@ use IQDEV\ElasticSearch\Search\Request; final class CriteriaToEsRequest { + public function __construct( + private readonly Configuration $configuration, + ) { + } + public function fromCriteria(Criteria $criteria): Request { $request = new Request(); + $request = $this->pagination($request, $criteria); $request = $this->order($request, $criteria); + $request = $this->search($request, $criteria); $request = $this->filter($request, $criteria); $request = $this->aggs($request, $criteria); @@ -47,7 +55,7 @@ final class CriteriaToEsRequest { $request = clone $request; - $request->setPagination(new Pagination($criteria->pagination()->limit, $criteria->pagination()->offset)); + $request->setPagination(new Pagination($criteria->getPagination()->limit, $criteria->getPagination()->offset)); return $request; } @@ -56,11 +64,11 @@ final class CriteriaToEsRequest { $request = clone $request; - if (true === $criteria->sorting()->isEmpty()) { + if (true === $criteria->getSorting()->isEmpty()) { return $request; } - foreach ($criteria->sorting() as $order) { + foreach ($criteria->getSorting() as $order) { /** @var Order $order */ $request->getSort()->add($order); } @@ -68,89 +76,172 @@ final class CriteriaToEsRequest return $request; } + private function search(Request $request, Criteria $criteria): Request + { + $request = clone $request; + + foreach ($criteria->getSearch() as $search) { + /** @var Search $search */ + $searchQuery = new SearchQuery($search); + + if ($search->getProperty()->getType() === PropertyType::TEXT) { + $request->getQueryMatch()->add($searchQuery->toQueryMatch()); + } else { + $request->getQuery()->getMust()->add($searchQuery->toMust($this->configuration)); + } + } + + return $request; + } + private function filter(Request $request, Criteria $criteria): Request { $request = clone $request; - if ($criteria->filters()->isEmpty()) { + if ($criteria->getFilters()->isEmpty()) { return $request; } - foreach ($criteria->filters() as $filterGroup) { - /** @var FilterGroupCollection $filterGroup */ - foreach ($filterGroup as $filter) { - /** @var Filter $filter */ - $value = $filter->value()->value(); - $field = $filter->field()->value(); + $queryFilters = $criteria->getFilters()->getFilterCollectionByType(FilterType::QUERY); + $postFilters = $criteria->getFilters()->getFilterCollectionByType(FilterType::POST); - if ('search' === $field) { - if ($filter->operator() === FilterOperator::CONTAINS) { - $request->addMatch( - 'suggest_search_content', - [ - 'query' => $value, - ], - ); - } else { - $request->addMatch( - 'full_search_content', - [ - 'query' => $value, - ], - ); - } - continue; - } + $this->addFilterToRequest($request, $queryFilters); + $this->addPostFilterToRequest($request, $postFilters); - if ('category_id' === $field) { - $request->getQuery()->must( - new Terms('category_id', $filter->value()->value()) - ); - continue; + return $request; + } + + private function separatePropertyTypes(FilterCollection $filterCollection): array + { + $propertyFilter = new FilterCollection(); + $nestedFilter = new FilterCollection(); + + foreach ($filterCollection as $groupFilter) { + /** @var FilterGroupCollection $groupFilter */ + $propertyGroupCollection = new FilterGroupCollection(); + $nestedGroupCollection = new FilterGroupCollection(); + + $propertyGroupCollection->setLogicOperator($groupFilter->getLogicOperator()); + $nestedGroupCollection->setLogicOperator($groupFilter->getLogicOperator()); + + foreach ($groupFilter as $filter) { + /** @var Filter $filter */ + if (true === MappingValidator::isPropertyExists($this->configuration, $filter->field()->value())) { + $propertyGroupCollection->add($filter); + } else { + $nestedGroupCollection->add($filter); } } + + if (false === $propertyGroupCollection->isEmpty()) { + $propertyFilter->add($propertyGroupCollection); + } + + if (false === $nestedGroupCollection->isEmpty()) { + $nestedFilter->add($nestedGroupCollection); + } } - [$queryFilters, $postFilters] = $this->groupFilters($criteria->filters()); + return [$propertyFilter, $nestedFilter]; + } - $keywordQueryFilter = $this->getKeywordFilter($queryFilters); - $keywordPostFilter = $this->getKeywordFilter($postFilters); - if (false === $keywordQueryFilter->isEmpty() || false === $keywordPostFilter->isEmpty()) { - $keywordNestedFilter = new Nested(); - $keywordNestedFilter->setPath('search_data'); + private function addFilterToRequest(Request $request, QueryFilterCollection $filterCollection): void + { + [$propertyFilterCollection, $nestedFilterCollection] = $this->separatePropertyTypes($filterCollection); - if (false === $keywordQueryFilter->isEmpty()) { - $keywordNestedFilterQuery = clone $keywordNestedFilter; - $keywordNestedFilterQuery->setQuery($keywordQueryFilter); - $request->getQuery()->filter($keywordNestedFilterQuery); - } + $this->addPropertyFilterToRequest($request, $propertyFilterCollection); + $this->addNestedFilterToRequest($request, $nestedFilterCollection); + } - if (false === $keywordPostFilter->isEmpty()) { - $keywordNestedFilterPost = clone $keywordNestedFilter; - $keywordNestedFilterPost->setQuery($keywordPostFilter); - $request->getPostFilter()->filter($keywordNestedFilterPost); - } + private function addPostFilterToRequest(Request $request, PostFilterCollection $filterCollection): void + { + [$propertyFilterCollection, $nestedFilterCollection] = $this->separatePropertyTypes($filterCollection); + + $this->addPropertyPostFilterToRequest($request, $propertyFilterCollection); + $this->addNestedPostFilterToRequest($request, $nestedFilterCollection); + } + + private function addPropertyFilterToRequest(Request $request, FilterCollection $filterCollection): void + { + $keywordFilterCollection = $this->getKeywordFilter($filterCollection); + foreach ($keywordFilterCollection->getFilter() as $filter) { + $request->getQuery()->getFilter()->add($filter); + } + foreach ($keywordFilterCollection->getShould() as $should) { + $request->getQuery()->getShould()->add($should); } - $numberQueryFilter = $this->getNumberFilter($queryFilters); - $numberPostFilter = $this->getNumberFilter($postFilters); - if (false === $numberQueryFilter->isEmpty() || false === $numberPostFilter->isEmpty()) { - $numberNestedFilter = new Nested(); - $numberNestedFilter->setPath('search_data'); + $numberFilterCollection = $this->getNumberFilter($filterCollection); + foreach ($numberFilterCollection->getFilter() as $filter) { + $request->getQuery()->getFilter()->add($filter); + } + foreach ($numberFilterCollection->getShould() as $should) { + $request->getQuery()->getShould()->add($should); + } + } - if (false === $numberQueryFilter->isEmpty()) { - $numberNestedFilterQuery = clone $numberNestedFilter; - $numberNestedFilterQuery->setQuery($numberQueryFilter); - $request->getQuery()->filter($numberNestedFilterQuery); - } + private function addPropertyPostFilterToRequest(Request $request, FilterCollection $filterCollection): void + { + $keywordFilterCollection = $this->getKeywordFilter($filterCollection); + foreach ($keywordFilterCollection->getFilter() as $filter) { + $request->getPostFilter()->getFilter()->add($filter); + } + foreach ($keywordFilterCollection->getShould() as $should) { + $request->getPostFilter()->getShould()->add($should); + } - if (false === $numberPostFilter->isEmpty()) { - $numberNestedFilterPost = clone $numberNestedFilter; - $numberNestedFilterPost->setQuery($numberPostFilter); - $request->getPostFilter()->filter($numberNestedFilterPost); - } + $numberFilterCollection = $this->getNumberFilter($filterCollection); + foreach ($numberFilterCollection->getFilter() as $filter) { + $request->getPostFilter()->getFilter()->add($filter); + } + foreach ($numberFilterCollection->getShould() as $should) { + $request->getPostFilter()->getShould()->add($should); } + } - return $request; + private function addNestedFilterToRequest(Request $request, FilterCollection $filterCollection): void + { + $keywordFilterCollection = $this->getKeywordFilter($filterCollection); + $keywordFilter = new Nested(); + $keywordFilter->setPath('search_data'); + + if (false === $keywordFilterCollection->isEmpty()) { + $keywordNestedFilterQuery = clone $keywordFilter; + $keywordNestedFilterQuery->setQuery($keywordFilterCollection); + $request->getQuery()->getFilter()->add($keywordNestedFilterQuery); + } + + $numberFilterCollection = $this->getNumberFilter($filterCollection); + $numberFilter = new Nested(); + $numberFilter->setPath('search_data'); + + if (false === $numberFilterCollection->isEmpty()) { + $numberNestedFilterQuery = clone $numberFilter; + $numberNestedFilterQuery->setQuery($numberFilterCollection); + $request->getQuery()->getFilter()->add($numberNestedFilterQuery); + } + } + + private function addNestedPostFilterToRequest(Request $request, FilterCollection $postFilter): void + { + $keywordFilterCollection = $this->getKeywordFilter($postFilter); + $keywordFilter = new Nested(); + $keywordFilter->setPath('search_data'); + + if (false === $keywordFilterCollection->isEmpty()) { + $keywordNestedFilterQuery = clone $keywordFilter; + $keywordNestedFilterQuery->setQuery($keywordFilterCollection); + $request->getPostFilter()->getFilter()->add($keywordNestedFilterQuery); + } + + $numberFilterCollection = $this->getNumberFilter($postFilter); + $numberFilter = new Nested(); + $numberFilter->setPath('search_data'); + + if (false === $numberFilterCollection->isEmpty()) { + $numberNestedFilterQuery = clone $numberFilter; + $numberNestedFilterQuery->setQuery($numberFilterCollection); + $request->getPostFilter()->getFilter()->add($numberNestedFilterQuery); + } } private function getNumberFilter(FilterCollection $filterCollection, array $excludeFilter = []): Query @@ -193,15 +284,16 @@ final class CriteriaToEsRequest if (false === empty($ranges)) { foreach ($ranges as $iGroup => $group) { foreach ($group as $field => $range) { - $facet = new FilterNumberFacet( + $isProperty = MappingValidator::isPropertyExists($this->configuration, $field); + $facet = $isProperty ? new Stats($field, $range) : new FilterNumberFacet( $field, $range ); if ($iGroup === 0) { - $numberFilter->filter($facet); + $numberFilter->getFilter()->add($facet); } else { - $numberFilter->should($facet); + $numberFilter->getShould()->add($facet); } } } @@ -228,6 +320,7 @@ final class CriteriaToEsRequest /** @var Filter $filter */ $value = $filter->value()->value(); $field = $filter->field()->value(); + $isProperty = MappingValidator::isPropertyExists($this->configuration, $field); if (in_array($field, $excludeFilter, true)) { continue; @@ -241,14 +334,6 @@ final class CriteriaToEsRequest continue; } - if ('search' === $field) { - continue; - } - - if ('category_id' === $field) { - continue; - } - if (is_array($value)) { $value = array_map(static fn($v) => (string)$v, $value); } else { @@ -256,9 +341,9 @@ final class CriteriaToEsRequest } if ($should) { - $keywordFilter->should(new FilterKeywordFacet($field, $value)); + $keywordFilter->getShould()->add($isProperty ? new Terms($field, $value) : new FilterKeywordFacet($field, $value)); } else { - $keywordFilter->filter(new FilterKeywordFacet($field, $value)); + $keywordFilter->getFilter()->add($isProperty ? new Terms($field, $value) : new FilterKeywordFacet($field, $value)); } } } @@ -270,7 +355,7 @@ final class CriteriaToEsRequest { $request = clone $request; - if ($criteria->filters()->isEmpty()) { + if ($criteria->getFilters()->isEmpty() && $criteria->getSearch()->isEmpty()) { return $request; } @@ -288,7 +373,7 @@ final class CriteriaToEsRequest ) ); - [$queryFilters, $postFilters] = $this->groupFilters($criteria->filters()); + $postFilters = $criteria->getFilters()->getFilterCollectionByType(FilterType::POST); $getKey = static fn(string $type, string $name): string => sprintf('%s_facet_%s', $type, $name); foreach ($postFilters as $filterGroup) { @@ -305,14 +390,6 @@ final class CriteriaToEsRequest continue; } - if ('search' === $field) { - continue; - } - - if ('category_id' === $field) { - continue; - } - if ($filter->value() instanceof FilterKeyword) { $aggsFiltered = new Aggs($getKey('keyword', $field)); $aggsFiltered->addAggs( @@ -329,14 +406,14 @@ final class CriteriaToEsRequest $nestedFilterKeyword = new Nested(); $nestedFilterKeyword->setPath('search_data') ->setQuery($keywordFilter); - $queryKeywordFiltered->filter($nestedFilterKeyword); + $queryKeywordFiltered->getFilter()->add($nestedFilterKeyword); } if (false === $numberFilter->isEmpty()) { $nestedFilterNumber = new Nested(); $nestedFilterNumber->setPath('search_data') ->setQuery($numberFilter); - $queryKeywordFiltered->filter($nestedFilterNumber); + $queryKeywordFiltered->getFilter()->add($nestedFilterNumber); } if ($queryKeywordFiltered->isEmpty() === false) { @@ -350,88 +427,61 @@ final class CriteriaToEsRequest } } - $keywordFilter = $this->getKeywordFilter($postFilters); - $numberFilter = $this->getNumberFilter($postFilters); - - $aggsKeywordFiltered = new Aggs('keyword_facet_filtered'); - $aggsKeywordFiltered->addAggs( - AggsFacetTerms::create( - 'all_keyword_facet_filtered', - 'keyword_facet' - ) - ); - $queryKeywordFiltered = new Query(); - - $aggsNumberFiltered = new Aggs('number_facet_filtered'); - $aggsNumberFiltered->addAggs( - AggsFacetStats::create( - 'all_number_facet_filtered', - 'number_facet' - ) - ); - $queryNumberFiltered = new Query(); - - if (false === $keywordFilter->isEmpty()) { - $nestedFilterKeyword = new Nested(); - $nestedFilterKeyword->setPath('search_data') - ->setQuery($keywordFilter); - - $queryKeywordFiltered->filter($nestedFilterKeyword); - $queryNumberFiltered->filter($nestedFilterKeyword); - } + $keywordFilter = $this->getKeywordFilter($postFilters); + $numberFilter = $this->getNumberFilter($postFilters); - if (false === $numberFilter->isEmpty()) { - $nestedFilterNumber = new Nested(); - $nestedFilterNumber->setPath('search_data') - ->setQuery($numberFilter); + $aggsKeywordFiltered = new Aggs('keyword_facet_filtered'); + $aggsKeywordFiltered->addAggs( + AggsFacetTerms::create( + 'all_keyword_facet_filtered', + 'keyword_facet' + ) + ); + $queryKeywordFiltered = new Query(); - $queryKeywordFiltered->filter($nestedFilterNumber); - $queryNumberFiltered->filter($nestedFilterNumber); - } + $aggsNumberFiltered = new Aggs('number_facet_filtered'); + $aggsNumberFiltered->addAggs( + AggsFacetStats::create( + 'all_number_facet_filtered', + 'number_facet' + ) + ); + $queryNumberFiltered = new Query(); - if (false === $queryKeywordFiltered->isEmpty()) { - $aggsKeywordFiltered->setQuery($queryKeywordFiltered); - } else { - $aggsKeywordFiltered->setNested((new Nested())->setPath('search_data')); - } + if (false === $keywordFilter->isEmpty()) { + $nestedFilterKeyword = new Nested(); + $nestedFilterKeyword->setPath('search_data') + ->setQuery($keywordFilter); - if (false === $queryNumberFiltered->isEmpty()) { - $aggsNumberFiltered->setQuery($queryNumberFiltered); - } else { - $aggsNumberFiltered->setNested((new Nested())->setPath('search_data')); - } + $queryKeywordFiltered->getFilter()->add($nestedFilterKeyword); + $queryNumberFiltered->getFilter()->add($nestedFilterKeyword); + } - $request->getAggs() - ->add($aggsKeywordFiltered) - ->add($aggsNumberFiltered); + if (false === $numberFilter->isEmpty()) { + $nestedFilterNumber = new Nested(); + $nestedFilterNumber->setPath('search_data') + ->setQuery($numberFilter); - return $request; - } + $queryKeywordFiltered->getFilter()->add($nestedFilterNumber); + $queryNumberFiltered->getFilter()->add($nestedFilterNumber); + } - /** - * @param FilterCollection $filters - * @return FilterCollection[] - */ - private function groupFilters(FilterCollection $filters): array - { - $queryFilters = new QueryFilterCollection(); - $postFilters = new PostFilterCollection(); - foreach ($filters as $filterGroup) { - /** @var FilterGroupCollection $filterGroup */ - if ($filterGroup->isEmpty()) { - continue; - } + if (false === $queryKeywordFiltered->isEmpty()) { + $aggsKeywordFiltered->setQuery($queryKeywordFiltered); + } else { + $aggsKeywordFiltered->setNested((new Nested())->setPath('search_data')); + } - switch ($filterGroup->getFilterType()->value()) { - case FilterType::QUERY: - $queryFilters->add($filterGroup); - break; - case FilterType::POST: - $postFilters->add($filterGroup); - break; - } + if (false === $queryNumberFiltered->isEmpty()) { + $aggsNumberFiltered->setQuery($queryNumberFiltered); + } else { + $aggsNumberFiltered->setNested((new Nested())->setPath('search_data')); } - return [$queryFilters, $postFilters]; + $request->getAggs() + ->add($aggsKeywordFiltered) + ->add($aggsNumberFiltered); + + return $request; } } diff --git a/src/ElasticSearch/Converter/CriteriaToRequest.php b/src/ElasticSearch/Converter/CriteriaToRequest.php new file mode 100644 index 0000000000000000000000000000000000000000..8efde5b386dc799047b95b9d7bbc1c04eda9d371 --- /dev/null +++ b/src/ElasticSearch/Converter/CriteriaToRequest.php @@ -0,0 +1,26 @@ +configuration, $criteria); + $builder->build(); + + return $builder->getRequest(); + } +} diff --git a/src/ElasticSearch/Converter/Request/Aggregation/Aggregation.php b/src/ElasticSearch/Converter/Request/Aggregation/Aggregation.php new file mode 100644 index 0000000000000000000000000000000000000000..a9b6f64f95403eff2060a5be3d31862e8f6f1a41 --- /dev/null +++ b/src/ElasticSearch/Converter/Request/Aggregation/Aggregation.php @@ -0,0 +1,67 @@ +convertToQuery(); + } + + public function convertToQuery(): void + { + $this->aggregations->add( + AggsFacetTerms::create( + 'keyword_facet', + 'keyword_facet' + ) + ); + + $this->aggregations->add( + AggsFacetStats::create( + 'number_facet', + 'number_facet' + ) + ); + + $postFilterCollection = $this->criteria->getFilters()->getFilterCollectionByType(FilterType::POST); + +// foreach ($postFilterCollection as $filterGroup) { +// /** @var FilterGroupCollection $filterGroup */ +// +// foreach ($filterGroup as $filter) { +// /** @var Filter $filter */ +// +// $filterAggregation = new FilterAggregation($this->configuration, $filter, $postFilterCollection); +// +// if ($aggregation = $filterAggregation->getFilterAggregation()) { +// $this->aggregations->add($aggregation); +// } +// } +// } + $fullAggregation = new FullAggregation($this->configuration, $postFilterCollection); + + $this->aggregations->add($fullAggregation->getKeywordAggregation()); + $this->aggregations->add($fullAggregation->getRangeAggregation()); + } + + public function getAggregation(): AggsCollection + { + return $this->aggregations; + } +} diff --git a/src/ElasticSearch/Converter/Request/Aggregation/FilterAggregation.php b/src/ElasticSearch/Converter/Request/Aggregation/FilterAggregation.php new file mode 100644 index 0000000000000000000000000000000000000000..9d3ff9e596c17a6a03e9ba726c5d5ee272739f64 --- /dev/null +++ b/src/ElasticSearch/Converter/Request/Aggregation/FilterAggregation.php @@ -0,0 +1,80 @@ +value() instanceof FilterKeyword) { + $this->setAggregation(); + } + } + + private function setAggregation(): void + { + $this->aggregation = new Aggs( + $this->getKey('keyword', $this->filter->field()->value()) + ); + + $this->aggregation->addAggs( + AggsFacetTerms::create( + 'agg_special', + 'keyword_facet' + ) + ); + +// $queryKeywordFiltered = new Query(); +// +// $keywordFilterCollection = $this->filterCollection->getKeywordFilters([$this->filter->field()->value()]); +// $rangeFilterCollection = $this->filterCollection->getNumberFilters(); +// +// $keywordFilterQuery = (new FilterQuery($this->configuration, $keywordFilterCollection))->getQuery(); +// $rangeFilterQuery = (new FilterQuery($this->configuration, $rangeFilterCollection))->getQuery(); +// +// if (false === $keywordFilterQuery->isEmpty()) { +// foreach ($keywordFilterQuery->getFilter() as $filter) { +// $queryKeywordFiltered->getFilter()->add($filter); +// } +// } +// +// if (false === $rangeFilterQuery->isEmpty()) { +// foreach ($rangeFilterQuery->getFilter() as $filter) { +// $queryKeywordFiltered->getFilter()->add($filter); +// } +// } +// +// if ($queryKeywordFiltered->isEmpty() === false) { +// $this->aggregation->setQuery($queryKeywordFiltered); +// } else { +// $this->aggregation->setNested((new Nested())->setPath('search_data')); +// } + } + + public function getFilterAggregation(): ?Aggs + { + return $this->aggregation; + } + + private function getKey(string $type, string $name): string + { + return sprintf('%s_facet_%s', $type, $name); + } +} diff --git a/src/ElasticSearch/Converter/Request/Aggregation/FullAggregation.php b/src/ElasticSearch/Converter/Request/Aggregation/FullAggregation.php new file mode 100644 index 0000000000000000000000000000000000000000..7cad438825cb7d0f38bf0838e0878bbe689b0a63 --- /dev/null +++ b/src/ElasticSearch/Converter/Request/Aggregation/FullAggregation.php @@ -0,0 +1,66 @@ +queryKeywordFiltered = new Query(); + $this->queryNumberFiltered = new Query(); + } + + public function getKeywordAggregation(): Aggs + { + $filterCollection = $this->filterCollection->getKeywordFilters(); + $keywordFilter = (new FilterQuery($this->configuration, $filterCollection))->getQuery(); + + + if (isset($GLOBALS['DD']) && $GLOBALS['DD'] === true) { + dump($filterCollection); + dd($keywordFilter->es()); + } + + $aggsKeywordFiltered = new Aggs('keyword_facet_filtered'); + $aggsKeywordFiltered->addAggs( + AggsFacetTerms::create( + 'all_keyword_facet_filtered', + 'keyword_facet' + ) + ); + + return $aggsKeywordFiltered; + } + + public function getRangeAggregation(): Aggs + { + $filterCollection = $this->filterCollection->getNumberFilters(); + + $aggsNumberFiltered = new Aggs('number_facet_filtered'); + $aggsNumberFiltered->addAggs( + AggsFacetStats::create( + 'all_number_facet_filtered', + 'number_facet' + ) + ); + + return $aggsNumberFiltered; + } +} diff --git a/src/ElasticSearch/Converter/Request/Collection/NestedFilterCollection.php b/src/ElasticSearch/Converter/Request/Collection/NestedFilterCollection.php new file mode 100644 index 0000000000000000000000000000000000000000..6e779de1b1eeed5c457eff46c689d430c6aef314 --- /dev/null +++ b/src/ElasticSearch/Converter/Request/Collection/NestedFilterCollection.php @@ -0,0 +1,11 @@ +setPagination(); + + if (false === $this->criteria->getSorting()->isEmpty()) { + $this->setSort(); + } + + if (false === $this->criteria->getSearch()->isEmpty()) { + $this->setSearch(); + } + + if (false === $this->criteria->getFilters()->isEmpty()) { + $this->setFilter(); + } + + if (false === $this->criteria->getSearch()->isEmpty() || false === $this->criteria->getFilters()->isEmpty()) { + $this->setAggregations(); + } + } + + public function setPagination(): void + { + $request = clone $this->request; + + $request->setPagination(new Pagination( + $this->criteria->getPagination()->limit, + $this->criteria->getPagination()->offset + )); + + $this->request = $request; + } + + public function setSort(): void + { + $request = clone $this->request; + + foreach ($this->criteria->getSorting() as $sort) { + $request->getSort()->add($sort); + } + + $this->request = $request; + } + + public function setSearch(): void + { + $request = clone $this->request; + + foreach ($this->criteria->getSearch() as $search) { + /** @var Search $search */ + $searchQuery = new SearchQuery($search); + + if ($search->getProperty()->getType() === PropertyType::TEXT) { + $request->getQueryMatch()->add($searchQuery->toQueryMatch()); + } else { + $request->getQuery()->getMust()->add($searchQuery->toMust($this->configuration)); + } + } + + $this->request = $request; + } + + public function setFilter(): void + { + $queryFilterCollection = $this->criteria->getFilters()->getQueryFilterCollection(); + if (false === $queryFilterCollection->isEmpty()) { + $this->setQueryFilter($queryFilterCollection); + } + + $postFilterCollection = $this->criteria->getFilters()->getPostFilterCollection(); + if (false === $postFilterCollection->isEmpty()) { + $this->setPostFilter($postFilterCollection); + } + } + + private function setQueryFilter(QueryFilterCollection $filterCollection): void + { + $request = clone $this->request; + + $filterQuery = new FilterQuery($this->configuration, $filterCollection); + $request->setQuery($filterQuery->getQuery()); + + $this->request = $request; + } + + private function setPostFilter(PostFilterCollection $filterCollection): void + { + $request = clone $this->request; + + $filterQuery = new FilterQuery($this->configuration, $filterCollection); + $request->setPostFilter($filterQuery->getQuery()); + + $this->request = $request; + } + + public function setAggregations(): void + { + $request = clone $this->request; + + $aggregation = new Aggregation($this->configuration, $this->criteria); + $request->setAggs($aggregation->getAggregation()); + + $this->request = $request; + } +} diff --git a/src/ElasticSearch/Converter/Request/Filter/AbstractFilterQuery.php b/src/ElasticSearch/Converter/Request/Filter/AbstractFilterQuery.php new file mode 100644 index 0000000000000000000000000000000000000000..f0a305acec5a9f859e0bcbad44d3495395e649c9 --- /dev/null +++ b/src/ElasticSearch/Converter/Request/Filter/AbstractFilterQuery.php @@ -0,0 +1,31 @@ +query = new Query(); + } + + protected function setFilterByLogic(LogicOperator $logicOperator, Esable $filter): void + { + match ($logicOperator) { + LogicOperator::AND => $this->query->getFilter()->add($filter), + LogicOperator::OR => $this->query->getShould()->add($filter), + LogicOperator::NOT => $this->query->getMustNot()->add($filter), + }; + } + + abstract public function getQuery(FilterGroupCollection $filterGroupCollection): Query|Nested; +} diff --git a/src/ElasticSearch/Converter/Request/Filter/NestedFilter.php b/src/ElasticSearch/Converter/Request/Filter/NestedFilter.php new file mode 100644 index 0000000000000000000000000000000000000000..f6796a59cdb63733e747a75a87fe8e40660051ad --- /dev/null +++ b/src/ElasticSearch/Converter/Request/Filter/NestedFilter.php @@ -0,0 +1,61 @@ +getKeywordFilters(); + foreach ($keywordFiltersGroup as $keywordFilter) { + /** @var Filter $keywordFilter */ + $esableFilter = new KeywordFilterType($keywordFilter); + + $this->setFilterByLogic($filterGroupCollection->getLogicOperator(), $this->getNested($esableFilter, self::NESTED_KEYWORD_PATH)); + } + + $rangeFilterGroup = $filterGroupCollection->getRangeFilters(); + $rangesFilter = RangeFilterType::getFiltersByOneProperty($rangeFilterGroup); + foreach ($rangesFilter as $filterGroup) { + /** @var FilterGroupCollection $filterGroup */ + + $esableFilter = new RangeFilterType($filterGroup); + $this->setFilterByLogic($filterGroupCollection->getLogicOperator(), $this->getNested($esableFilter, self::NESTED_RANGE_PATH)); + } + + return (new Nested()) + ->setPath('search_data') + ->setQuery($this->query); + } + + private function getNested(RangeFilterType|KeywordFilterType $filter, string $path): Nested + { + $cloneFilter = clone $filter; + $nested = new Nested(); + $query = new Query(); + + $query->getFilter()->add(new Terms($path . '.facet_code', $cloneFilter->getField())); + + $cloneFilter->setField($path . '.facet_value'); + $query->getFilter()->add($cloneFilter->getEsable()); + + $nested + ->setPath($path) + ->setQuery($query); + + return $nested; + } +} diff --git a/src/ElasticSearch/Converter/Request/Filter/PropertyFilter.php b/src/ElasticSearch/Converter/Request/Filter/PropertyFilter.php new file mode 100644 index 0000000000000000000000000000000000000000..536ebaf893969038336fdfea41e1662dfc4217c9 --- /dev/null +++ b/src/ElasticSearch/Converter/Request/Filter/PropertyFilter.php @@ -0,0 +1,36 @@ +getKeywordFilters(); + foreach ($keywordFiltersGroup as $keywordFilter) { + /** @var Filter $keywordFilter */ + $esableFilter = new KeywordFilterType($keywordFilter); + + $this->setFilterByLogic($filterGroupCollection->getLogicOperator(), $esableFilter->getEsable()); + } + + $rangeFilterGroup = $filterGroupCollection->getRangeFilters(); + $rangesFilter = RangeFilterType::getFiltersByOneProperty($rangeFilterGroup); + foreach ($rangesFilter as $filterGroup) { + /** @var FilterGroupCollection $filterGroup */ + + $esableFilter = new RangeFilterType($filterGroup); + $this->setFilterByLogic($filterGroupCollection->getLogicOperator(), $esableFilter->getEsable()); + } + + return $this->query; + } +} diff --git a/src/ElasticSearch/Converter/Request/Filter/Type/AbstractFilterType.php b/src/ElasticSearch/Converter/Request/Filter/Type/AbstractFilterType.php new file mode 100644 index 0000000000000000000000000000000000000000..c292b8b18c8bf0ab7380b86a7a8a9e56b137645e --- /dev/null +++ b/src/ElasticSearch/Converter/Request/Filter/Type/AbstractFilterType.php @@ -0,0 +1,21 @@ +field; + } + + public function setField(string $field): self + { + $this->field = $field; + return $this; + } +} diff --git a/src/ElasticSearch/Converter/Request/Filter/Type/KeywordFilterType.php b/src/ElasticSearch/Converter/Request/Filter/Type/KeywordFilterType.php new file mode 100644 index 0000000000000000000000000000000000000000..f78e18a35401ca4e2c9fd722b2058ff0823cf10f --- /dev/null +++ b/src/ElasticSearch/Converter/Request/Filter/Type/KeywordFilterType.php @@ -0,0 +1,23 @@ +field = $this->filter->field()->value(); + } + + public function getEsable(): Esable + { + return new Terms($this->field, $this->filter->value()->value()); + } +} diff --git a/src/ElasticSearch/Converter/Request/Filter/Type/RangeFilterType.php b/src/ElasticSearch/Converter/Request/Filter/Type/RangeFilterType.php new file mode 100644 index 0000000000000000000000000000000000000000..fcf6a2a6fb4d0b686d89599ad1d194004b2b05d4 --- /dev/null +++ b/src/ElasticSearch/Converter/Request/Filter/Type/RangeFilterType.php @@ -0,0 +1,52 @@ +field = $this->filterGroupCollection->first()->field()->value(); + } + + public function getEsable(): Esable + { + $ranges = []; + + foreach ($this->filterGroupCollection as $filter) { + /** @var Filter $filter */ + + $value = $filter->value()->value(); + $ranges[$filter->operator()->value] = $value; + } + + return new Stats($this->field, $ranges); + } + + public static function getFiltersByOneProperty(FilterGroupCollection $filterGroupCollection): FilterCollection + { + $rangeFilters = new FilterCollection(); + + $properties = []; + foreach ($filterGroupCollection as $filter) { + /** @var Filter $filter */ + + $properties[$filter->field()->value()][] = $filter; + } + + foreach ($properties as $propertyFilters) { + $rangeFilters->add(new FilterGroupCollection($propertyFilters)); + } + + return $rangeFilters; + } +} diff --git a/src/ElasticSearch/Converter/Request/FilterQuery.php b/src/ElasticSearch/Converter/Request/FilterQuery.php new file mode 100644 index 0000000000000000000000000000000000000000..d9c297161586dcff1b024fd26475222ba5f89044 --- /dev/null +++ b/src/ElasticSearch/Converter/Request/FilterQuery.php @@ -0,0 +1,110 @@ +query = new Query(); + $this->convertToQuery(); + } + + private function convertToQuery(): void + { + [$propertyFilterCollection, $nestedFilterCollection] = $this->separatePropertyTypes($this->filterCollection); + + $this->fillQuery($propertyFilterCollection, new PropertyFilter()); + $this->fillQuery($nestedFilterCollection, new NestedFilter()); + } + + private function fillQuery(FilterCollection $filterCollection, AbstractFilterQuery $filterQuery): void + { + foreach ($filterCollection as $filterGroup) { + /** @var FilterGroupCollection $filterGroup */ + + $this->setQuery($filterGroup, $filterQuery); + } + } + + private function setQuery(FilterGroupCollection $filterGroup, AbstractFilterQuery $filterQuery): void + { + $filters = $filterQuery->getQuery($filterGroup); + + if ($filters instanceof Query) { + foreach ($filters->getFilter() as $filter) { + $this->query->getFilter()->add($filter); + } + + foreach ($filters->getShould() as $filter) { + $this->query->getShould()->add($filter); + } + + foreach ($filters->getMustNot() as $filter) { + $this->query->getMustNot()->add($filter); + } + + $this->query = $filters; + } elseif ($filters instanceof Nested) { + $this->query->getFilter()->add($filters); + } + } + + public function getQuery(): Query + { + return $this->query; + } + + private function separatePropertyTypes(FilterCollection $filterCollection): array + { + $propertyFilter = new PropertyFilterCollection(); + $nestedFilter = new NestedFilterCollection(); + + foreach ($filterCollection as $groupFilter) { + /** @var FilterGroupCollection $groupFilter */ + $propertyGroupCollection = new FilterGroupCollection(); + $nestedGroupCollection = new FilterGroupCollection(); + + $propertyGroupCollection->setLogicOperator($groupFilter->getLogicOperator()); + $nestedGroupCollection->setLogicOperator($groupFilter->getLogicOperator()); + + foreach ($groupFilter as $filter) { + /** @var Filter $filter */ + if (true === MappingValidator::isPropertyExists($this->configuration, $filter->field()->value())) { + $propertyGroupCollection->add($filter); + } else { + $nestedGroupCollection->add($filter); + } + } + + if (false === $propertyGroupCollection->isEmpty()) { + $propertyFilter->add($propertyGroupCollection); + } + + if (false === $nestedGroupCollection->isEmpty()) { + $nestedFilter->add($nestedGroupCollection); + } + } + + return [$propertyFilter, $nestedFilter]; + } +} diff --git a/src/ElasticSearch/Converter/Request/RequestBuilder.php b/src/ElasticSearch/Converter/Request/RequestBuilder.php new file mode 100644 index 0000000000000000000000000000000000000000..08646d6c5bf5ce001c0ea9b94425952af66d5523 --- /dev/null +++ b/src/ElasticSearch/Converter/Request/RequestBuilder.php @@ -0,0 +1,27 @@ +request; + } + + abstract public function setPagination(): void; + abstract public function setSort(): void; + abstract public function setSearch(): void; + abstract public function setFilter(): void; + abstract public function setAggregations(): void; + abstract public function build(): void; +} diff --git a/src/ElasticSearch/Criteria.php b/src/ElasticSearch/Criteria.php index 7b49d6a2a2d57c784dc76e70c065397d058df249..d3b33865e3155c0b2b2f96d52fcc549098e43c0c 100644 --- a/src/ElasticSearch/Criteria.php +++ b/src/ElasticSearch/Criteria.php @@ -2,33 +2,41 @@ namespace IQDEV\ElasticSearch; -use IQDEV\ElasticSearch\Filter\Collection\FilterCollection; -use IQDEV\ElasticSearch\Order\OrderCollection; +use IQDEV\ElasticSearch\Request\Filter\Collection\FilterCollection; +use IQDEV\ElasticSearch\Request\Order\OrderCollection; +use IQDEV\ElasticSearch\Request\Search\SearchCollection; final class Criteria { + private SearchCollection $search; private FilterCollection $filters; private OrderCollection $sorting; private Pagination $pagination; public function __construct() { + $this->search = new SearchCollection(); $this->filters = new FilterCollection(); $this->sorting = new OrderCollection(); $this->pagination = new Pagination(); } - public function filters(): FilterCollection + public function getSearch(): SearchCollection + { + return $this->search; + } + + public function getFilters(): FilterCollection { return $this->filters; } - public function sorting(): OrderCollection + public function getSorting(): OrderCollection { return $this->sorting; } - public function pagination(): Pagination + public function getPagination(): Pagination { return $this->pagination; } diff --git a/src/ElasticSearch/Document/Property/PropertyType.php b/src/ElasticSearch/Document/Property/PropertyType.php index 17476b37966608f4fca409527eef920bea71bb43..b611b3d4b39c4cc860932fe39983961aaf08e9da 100644 --- a/src/ElasticSearch/Document/Property/PropertyType.php +++ b/src/ElasticSearch/Document/Property/PropertyType.php @@ -7,4 +7,5 @@ enum PropertyType case BASE; case KEYWORD; case NUMBER; + case TEXT; } diff --git a/src/ElasticSearch/Filter/Collection/FilterCollection.php b/src/ElasticSearch/Filter/Collection/FilterCollection.php deleted file mode 100644 index 725076d3f207284087e728434bdfd409f08735e3..0000000000000000000000000000000000000000 --- a/src/ElasticSearch/Filter/Collection/FilterCollection.php +++ /dev/null @@ -1,56 +0,0 @@ -type = LogicOperator::AND; - } - - /** - * @inheritDoc - */ - public function getType(): string - { - return FilterGroupCollection::class; - } - - /** - * Установка типа логической операции - * - * @param LogicOperator $type - * - * @return $this - */ - public function setLogicalType(LogicOperator $type): self - { - $this->type = $type; - - return $this; - } - - /** - * Получение типа логической операции - * - * @return LogicOperator - */ - public function getLogicalType(): LogicOperator - { - return $this->type; - } -} diff --git a/src/ElasticSearch/Filter/FilterType.php b/src/ElasticSearch/Filter/FilterType.php deleted file mode 100644 index 732db069451bb2d32e74a5c8e947cb7ba8fdfea4..0000000000000000000000000000000000000000 --- a/src/ElasticSearch/Filter/FilterType.php +++ /dev/null @@ -1,52 +0,0 @@ -operator = $operator; - } - - public function value(): string - { - return $this->operator; - } - - /** - * @return string[] - */ - public static function toArray(): array - { - return [ - self::POST, - self::QUERY - ]; - } - - public static function __callStatic($method, $arguments) - { - if (in_array($method, self::toArray())) { - return new self($method); - } - } -} diff --git a/src/ElasticSearch/Indexer/EsHelperEndpoint.php b/src/ElasticSearch/Indexer/EsHelperEndpoint.php index 2977127efffb28ea91dcf05db5b1327ec86afb7d..4180c30266119035686fa8367a59e1a0ca25b51f 100644 --- a/src/ElasticSearch/Indexer/EsHelperEndpoint.php +++ b/src/ElasticSearch/Indexer/EsHelperEndpoint.php @@ -53,7 +53,7 @@ final class EsHelperEndpoint [ 'index' => $this->configuration->getIndexName(), 'body' => [ - 'mappings' => $this->configuration->getMapping(), + 'mappings' => $this->configuration->getMapping()->es(), 'settings' => $this->configuration->getSettings(), ], ] @@ -99,7 +99,7 @@ final class EsHelperEndpoint 'Accept' => 'application/json', 'Content-Type' => 'application/json', ], - $this->configuration->getMapping(), + $this->configuration->getMapping()->es(), ) ); diff --git a/src/ElasticSearch/Mapping.php b/src/ElasticSearch/Mapping.php new file mode 100644 index 0000000000000000000000000000000000000000..ba1ab6e1658a48a3c3c640d6168642834762ca78 --- /dev/null +++ b/src/ElasticSearch/Mapping.php @@ -0,0 +1,53 @@ + 'nested', + 'properties' => [ + 'keyword_facet' => [ + 'type' => 'nested', + 'properties' => [ + 'facet_code' => [ + 'type' => 'keyword', + 'index' => true + ], + 'facet_value' => [ + 'type' => 'keyword', + 'index' => true + ] + ] + ], + 'number_facet' => [ + 'type' => 'nested', + 'properties' => [ + 'facet_code' => [ + 'type' => 'keyword', + 'index' => true + ], + 'facet_value' => [ + 'type' => 'double' + ] + ] + ] + ] + ]; + } + + public function es(): array + { + return [ + 'properties' => array_merge( + $this->getPropertiesMap(), + ['search_data' => $this->getSearchDataMap()], + ) + ]; + } +} diff --git a/src/ElasticSearch/Request/Filter/Collection/FilterCollection.php b/src/ElasticSearch/Request/Filter/Collection/FilterCollection.php new file mode 100644 index 0000000000000000000000000000000000000000..66bac0663358c507f755f2d1ce4a9121903f731b --- /dev/null +++ b/src/ElasticSearch/Request/Filter/Collection/FilterCollection.php @@ -0,0 +1,172 @@ +type = LogicOperator::AND; + } + + /** + * @inheritDoc + */ + public function getType(): string + { + return FilterGroupCollection::class; + } + + /** + * Установка типа логической операции + * + * @param LogicOperator $type + * + * @return $this + */ + public function setLogicalType(LogicOperator $type): self + { + $this->type = $type; + + return $this; + } + + /** + * Получение типа логической операции + * + * @return LogicOperator + */ + public function getLogicalType(): LogicOperator + { + return $this->type; + } + + public function getFilterCollectionByType(FilterType $type): PostFilterCollection|QueryFilterCollection + { + $collection = match ($type) { + FilterType::POST => new PostFilterCollection(), + FilterType::QUERY => new QueryFilterCollection(), + }; + + $collection->data = array_filter( + $this->toArray(), + static fn (FilterGroupCollection $group) => $group->getFilterType() === $type + ); + + return $collection; + } + + public function getQueryFilterCollection(): QueryFilterCollection + { + $collection = new QueryFilterCollection(); + + $collection->data = array_filter( + $this->toArray(), + static fn (FilterGroupCollection $group) => $group->getFilterType() === FilterType::QUERY + ); + + return $collection; + } + + public function getPostFilterCollection(): PostFilterCollection + { + $collection = new PostFilterCollection(); + + $collection->data = array_filter( + $this->toArray(), + static fn (FilterGroupCollection $group) => $group->getFilterType() === FilterType::POST + ); + + return $collection; + } + + public function getKeywordFilters(array $excludeFilter = []): FilterCollection + { + $filterCollection = new FilterCollection(); + + foreach ($this->data as $filterGroup) { + /** @var FilterGroupCollection $filterGroup */ + + $keywordFilterGroup = new FilterGroupCollection(); + + foreach ($filterGroup->data as $filter) { + /** @var Filter $filter */ + + $field = $filter->field()->value(); + + if (in_array($field, $excludeFilter, true) + || in_array($filter->operator(), [ + FilterOperator::LT, + FilterOperator::LTE, + FilterOperator::GT, + FilterOperator::GTE + ], true) + ) { + continue; + } + + $keywordFilterGroup->add($filter); + } + + if (false === $keywordFilterGroup->isEmpty()) { + $keywordFilterGroup->setLogicOperator($filterGroup->getLogicOperator()); + $filterCollection->add($keywordFilterGroup); + } + } + + return $filterCollection; + } + + public function getNumberFilters(array $excludeFilter = []): FilterCollection + { + $filterCollection = new FilterCollection(); + + foreach ($this as $filterGroup) { + /** @var FilterGroupCollection $filterGroup */ + + $numberFilterGroup = new FilterGroupCollection(); + + foreach ($filterGroup as $filter) { + /** @var Filter $filter */ + + $field = $filter->field()->value(); + + if (in_array($field, $excludeFilter, true)) { + continue; + } + + if (in_array($filter->operator(), [ + FilterOperator::LT, + FilterOperator::LTE, + FilterOperator::GT, + FilterOperator::GTE + ], true)) { + $numberFilterGroup->add($filter); + } + } + + if (false === $numberFilterGroup->isEmpty()) { + $numberFilterGroup->setLogicOperator($filterGroup->getLogicOperator()); + $filterCollection->add($numberFilterGroup); + } + } + + return $filterCollection; + } +} diff --git a/src/ElasticSearch/Filter/Collection/FilterGroupCollection.php b/src/ElasticSearch/Request/Filter/Collection/FilterGroupCollection.php similarity index 54% rename from src/ElasticSearch/Filter/Collection/FilterGroupCollection.php rename to src/ElasticSearch/Request/Filter/Collection/FilterGroupCollection.php index 03b31353e54a915ba0d99a0421cc55b3f9401b04..0549fb2787568439a74aeae34a5edb61c2e6821a 100644 --- a/src/ElasticSearch/Filter/Collection/FilterGroupCollection.php +++ b/src/ElasticSearch/Request/Filter/Collection/FilterGroupCollection.php @@ -1,10 +1,11 @@ logicOperator = LogicOperator::AND; - $this->filterType = FilterType::post(); + $this->filterType = FilterType::POST; } /** @@ -82,4 +83,39 @@ class FilterGroupCollection extends AbstractCollection { return $this->filterType; } + + public function getKeywordFilters(array $excludeFilter = []): FilterGroupCollection + { + return $this->getFilters(false, $excludeFilter); + } + + public function getRangeFilters(array $excludeFilter = []): FilterGroupCollection + { + return $this->getFilters(true, $excludeFilter); + } + + private function getFilters(bool $range = false, array $excludeFilter = []): FilterGroupCollection + { + $filterGroup = new FilterGroupCollection(); + $filterGroup->setLogicOperator($this->getLogicOperator()); + + foreach ($this->data as $filter) { + /** @var Filter $filter */ + + $field = $filter->field()->value(); + + if (false === in_array($field, $excludeFilter, true) + && $range === in_array($filter->operator(), [ + FilterOperator::LT, + FilterOperator::LTE, + FilterOperator::GT, + FilterOperator::GTE + ], true) + ) { + $filterGroup->add($filter); + } + } + + return $filterGroup; + } } diff --git a/src/ElasticSearch/Filter/Collection/PostFilterCollection.php b/src/ElasticSearch/Request/Filter/Collection/PostFilterCollection.php similarity index 52% rename from src/ElasticSearch/Filter/Collection/PostFilterCollection.php rename to src/ElasticSearch/Request/Filter/Collection/PostFilterCollection.php index 482c5d5e7ef64d7eb6844d842b7981b2ba6862eb..c561c00cf1f749b765b83baab3539a31040a0f6d 100644 --- a/src/ElasticSearch/Filter/Collection/PostFilterCollection.php +++ b/src/ElasticSearch/Request/Filter/Collection/PostFilterCollection.php @@ -1,6 +1,6 @@ key => [ + 'query' => $this->value + ] + ]; + } +} diff --git a/src/ElasticSearch/Request/Match/QueryMatchCollection.php b/src/ElasticSearch/Request/Match/QueryMatchCollection.php new file mode 100644 index 0000000000000000000000000000000000000000..dcd5094d8c544027216541316cac69ad553c0085 --- /dev/null +++ b/src/ElasticSearch/Request/Match/QueryMatchCollection.php @@ -0,0 +1,31 @@ +toArray() as $match) { + /** @var QueryMatch $match */ + $matches = array_merge($match->es()); + } + + return $matches; + } +} diff --git a/src/ElasticSearch/Order/Order.php b/src/ElasticSearch/Request/Order/Order.php similarity index 93% rename from src/ElasticSearch/Order/Order.php rename to src/ElasticSearch/Request/Order/Order.php index 056001117ad498fc82ed4ea2c82d7b5723a2e719..802b6dd556a558e5cf6d6a83aafcdd9bc37c71bd 100644 --- a/src/ElasticSearch/Order/Order.php +++ b/src/ElasticSearch/Request/Order/Order.php @@ -1,6 +1,6 @@ property; + } + + public function getValue(): string + { + return $this->value; + } +} diff --git a/src/ElasticSearch/Request/Search/SearchCollection.php b/src/ElasticSearch/Request/Search/SearchCollection.php new file mode 100644 index 0000000000000000000000000000000000000000..8bcddb17188846afea7046fecbbc581c6a904df2 --- /dev/null +++ b/src/ElasticSearch/Request/Search/SearchCollection.php @@ -0,0 +1,16 @@ +search->getProperty()->getKey(), + $this->search->getValue(), + ); + } + + public function toMust(Configuration $configuration): Terms|Nested + { + if (MappingValidator::isPropertyExists($configuration, $this->search->getProperty()->getKey())) { + + return new Terms($this->search->getProperty()->getKey(), $this->search->getValue()); + } else { + $path = 'search_data.keyword_facet'; + + $nested = new Nested(); + + $query = new Query(); + $query->getFilter()->add(new Terms($path . '.facet_code', $this->search->getProperty()->getKey())); + $query->getFilter()->add(new Terms($path . '.facet_value', $this->search->getValue())); + + $nested + ->setPath($path) + ->setQuery($query); + + return $nested; + } + } +} diff --git a/src/ElasticSearch/Search/BoolQuery/FilterKeywordFacet.php b/src/ElasticSearch/Search/BoolQuery/FilterKeywordFacet.php index 1d20b8213233fbbd547d40ebb1760d0136dc61ea..b781ea7c31568e7bccec6135c3254a320c7b198a 100644 --- a/src/ElasticSearch/Search/BoolQuery/FilterKeywordFacet.php +++ b/src/ElasticSearch/Search/BoolQuery/FilterKeywordFacet.php @@ -24,9 +24,8 @@ final class FilterKeywordFacet implements Esable $nested = new Nested(); $query = new Query(); - $query - ->filter(new Terms($path . '.facet_code', $this->key)) - ->filter(new Terms($path . '.facet_value', $this->value)); + $query->getFilter()->add(new Terms($path . '.facet_code', $this->key)); + $query->getFilter()->add(new Terms($path . '.facet_value', $this->value)); $nested ->setPath($path) diff --git a/src/ElasticSearch/Search/BoolQuery/FilterNumberFacet.php b/src/ElasticSearch/Search/BoolQuery/FilterNumberFacet.php index 1bbad0a8af3fc777b9001004d13afd41cea8e686..f87777225cb5e3e53bd92943a56afd8ca2f3c6d1 100644 --- a/src/ElasticSearch/Search/BoolQuery/FilterNumberFacet.php +++ b/src/ElasticSearch/Search/BoolQuery/FilterNumberFacet.php @@ -3,8 +3,8 @@ namespace IQDEV\ElasticSearch\Search\BoolQuery; use IQDEV\ElasticSearch\Esable; +use IQDEV\ElasticSearch\Request\Filter\FilterOperator; use IQDEV\ElasticSearch\Search\Nested; -use IQDEV\ElasticSearch\Filter\FilterOperator; final class FilterNumberFacet implements Esable { @@ -23,7 +23,7 @@ final class FilterNumberFacet implements Esable $query = new Query(); $query - ->filter(new Stats($path.'.facet_code', $this->key)); + ->getFilter()->add(new Stats($path.'.facet_code', $this->key)); $conditions = []; foreach ($this->conditions as $operator => $value) { @@ -38,7 +38,7 @@ final class FilterNumberFacet implements Esable $conditions[$key] = $value; } } - $query->filter(new Stats($path.'.facet_value', $conditions)); + $query->getFilter()->add(new Stats($path.'.facet_value', $conditions)); $nested ->setPath($path) diff --git a/src/ElasticSearch/Search/BoolQuery/Query.php b/src/ElasticSearch/Search/BoolQuery/Query.php index e027710fd38f4e1db58e547336ef24e91ed6d15f..ff45c1a1a3a01f8de34d295bd5581400ff8f1f71 100644 --- a/src/ElasticSearch/Search/BoolQuery/Query.php +++ b/src/ElasticSearch/Search/BoolQuery/Query.php @@ -32,43 +32,34 @@ final class Query implements Esable * @param Terms|Nested $item * @return $this */ - public function match($item): self + public function getMatch(): BoolQueryCollection { - $this->match->add($item); - - return $this; + return $this->match; } - /** - * @param Terms|Nested $item - * @return $this - */ - public function must($item): self + public function getMust(): BoolQueryCollection { - $this->must->add($item); - - return $this; + return $this->must; } - public function filter(Esable $item): self + public function getFilter(): BoolQueryCollection { - $this->filter->add($item); - - return $this; + return $this->filter; } - public function should(Esable $item): self + public function setFilter(BoolQueryCollection $filter): BoolQueryCollection { - $this->should->add($item); - - return $this; + return $this->filter; } - public function mustNot(Esable $item): self + public function getShould(): BoolQueryCollection { - $this->mustNot->add($item); + return $this->should; + } - return $this; + public function getMustNot(): BoolQueryCollection + { + return $this->mustNot; } public function isEmpty(): bool diff --git a/src/ElasticSearch/Search/Request.php b/src/ElasticSearch/Search/Request.php index 99eb6a0ed299a36c23e5e0e644b23a91849d6e2e..88f41f18c66ab2bf4cddf0d6be4957b3de59d18d 100644 --- a/src/ElasticSearch/Search/Request.php +++ b/src/ElasticSearch/Search/Request.php @@ -3,7 +3,8 @@ namespace IQDEV\ElasticSearch\Search; use IQDEV\ElasticSearch\Esable; -use IQDEV\ElasticSearch\Order\OrderCollection; +use IQDEV\ElasticSearch\Request\Match\QueryMatchCollection; +use IQDEV\ElasticSearch\Request\Order\OrderCollection; use IQDEV\ElasticSearch\Search\Aggs\AggsCollection; use IQDEV\ElasticSearch\Search\BoolQuery\Query; @@ -14,7 +15,7 @@ final class Request implements Esable private ?AggsCollection $aggs = null; private ?Pagination $pagination = null; private ?OrderCollection $sort = null; - private array $match = []; + private ?QueryMatchCollection $matchCollection = null; private ?array $source = null; public function setPagination(?Pagination $pagination): self @@ -33,6 +34,13 @@ final class Request implements Esable return $this->query; } + public function setQuery(Query $query): self + { + $this->query = $query; + + return $this; + } + public function getPostFilter(): Query { if (null === $this->postFilter) { @@ -42,6 +50,13 @@ final class Request implements Esable return $this->postFilter; } + public function setPostFilter(Query $query): self + { + $this->postFilter = $query; + + return $this; + } + public function getAggs(): AggsCollection { if (null === $this->aggs) { @@ -51,16 +66,25 @@ final class Request implements Esable return $this->aggs; } - public function getPagination(): ?Pagination + public function setAggs(AggsCollection $aggs): self { - return $this->pagination; + $this->aggs = $aggs; + + return $this; } - public function addMatch(string $key, array $param): self + public function getQueryMatch(): QueryMatchCollection { - $this->match[$key] = $param; + if (null === $this->matchCollection) { + $this->matchCollection = new QueryMatchCollection(); + } - return $this; + return $this->matchCollection; + } + + public function getPagination(): ?Pagination + { + return $this->pagination; } public function setSource(array $s): self @@ -95,10 +119,8 @@ final class Request implements Esable $request['query'] = $this->query->es()['query']; } - if (false === empty($this->match)) { - foreach ($this->match as $key => $value) { - $request['query']['match'][$key] = $value; - } + if ($this->matchCollection && false === $this->matchCollection->isEmpty()) { + $request['query']['match'] = $this->matchCollection->es(); } if ($this->aggs) { diff --git a/src/ElasticSearch/SearchService.php b/src/ElasticSearch/SearchService.php index 518dedb56e0b09fab684936028c720b5f297b168..e3b70ce0b2c10144d1fe3ef2f0428ee67018fe6d 100644 --- a/src/ElasticSearch/SearchService.php +++ b/src/ElasticSearch/SearchService.php @@ -5,19 +5,19 @@ namespace IQDEV\ElasticSearch; use Elastic\Elasticsearch\Client; use Elastic\Elasticsearch\Exception\ClientResponseException; use Elastic\Elasticsearch\Exception\ServerResponseException; -use IQDEV\ElasticSearch\Converter\CriteriaToEsRequest; +use IQDEV\ElasticSearch\Converter\CriteriaToRequest; use IQDEV\ElasticSearch\Converter\EsResponseToResult; class SearchService implements Searchable { - private CriteriaToEsRequest $criteriaToEsRequest; + private CriteriaToRequest $criteriaToEsRequest; private EsResponseToResult $esResponseToResult; public function __construct( private Client $esClient, private Configuration $configuration ) { - $this->criteriaToEsRequest = new CriteriaToEsRequest(); + $this->criteriaToEsRequest = new CriteriaToRequest($this->configuration); $this->esResponseToResult = new EsResponseToResult(); } diff --git a/tests/Filter/AggsTest.php b/tests/Filter/AggsTest.php index 428fa6bc687eb1f61dce4bab3b9bd9a2ea473dd2..0de8e5b29e7a68458c554e330190c45ee79f0986 100644 --- a/tests/Filter/AggsTest.php +++ b/tests/Filter/AggsTest.php @@ -3,15 +3,16 @@ namespace IQDEV\ElasticSearchTests\Filter; use IQDEV\ElasticSearch\Criteria; -use IQDEV\ElasticSearch\Filter\Collection\FilterGroupCollection; -use IQDEV\ElasticSearch\Filter\Field; -use IQDEV\ElasticSearch\Filter\Filter; -use IQDEV\ElasticSearch\Filter\FilterOperator; -use IQDEV\ElasticSearch\Filter\FilterType; -use IQDEV\ElasticSearch\Filter\LogicOperator; -use IQDEV\ElasticSearch\Filter\Value\FilterKeyword; -use IQDEV\ElasticSearch\Filter\Value\FilterNumber; -use IQDEV\ElasticSearch\Query\SearchQuery; +use IQDEV\ElasticSearch\Document\Property\Property; +use IQDEV\ElasticSearch\Request\Filter\Collection\FilterGroupCollection; +use IQDEV\ElasticSearch\Request\Filter\Field; +use IQDEV\ElasticSearch\Request\Filter\Filter; +use IQDEV\ElasticSearch\Request\Filter\FilterOperator; +use IQDEV\ElasticSearch\Request\Filter\LogicOperator; +use IQDEV\ElasticSearch\Request\Filter\Value\FilterKeyword; +use IQDEV\ElasticSearch\Request\Filter\Value\FilterNumber; +use IQDEV\ElasticSearch\Request\Query\SearchQuery; +use IQDEV\ElasticSearch\Request\Search\Search; use IQDEV\ElasticSearchTests\AbstractTestCase; use IQDEV\ElasticSearchTests\Helpers\FormatData; use IQDEV\ElasticSearchTests\Service\SearchClient; @@ -24,16 +25,11 @@ class AggsTest extends AbstractTestCase public function testEmptyFilterByCategory() { $criteria = new Criteria(); - - $criteria->filters()->add( - (new FilterGroupCollection([ - new Filter( - new Field('category_id'), - FilterOperator::EQ, - new FilterKeyword('t-short') - ) - ])) - ->setFilterType(FilterType::query()) + $criteria->getSearch()->add( + new Search( + new Property('category_id'), + 't-short', + ), ); $q = new SearchQuery($criteria); @@ -146,19 +142,14 @@ class AggsTest extends AbstractTestCase public function testEmptyKeywordFilter() { $criteria = new Criteria(); - - $criteria->filters()->add( - (new FilterGroupCollection([ - new Filter( - new Field('category_id'), - FilterOperator::EQ, - new FilterKeyword('t-short') - ) - ])) - ->setFilterType(FilterType::query()) + $criteria->getSearch()->add( + new Search( + new Property('category_id'), + 't-short', + ), ); - $criteria->filters()->add(new FilterGroupCollection([ + $criteria->getFilters()->add(new FilterGroupCollection([ new Filter( new Field('color'), FilterOperator::EQ, @@ -275,19 +266,13 @@ class AggsTest extends AbstractTestCase public function testRangeFilter() { $criteria = new Criteria(); - - $criteria->filters()->add( - (new FilterGroupCollection([ - new Filter( - new Field('category_id'), - FilterOperator::EQ, - new FilterKeyword('t-short') - ) - ])) - ->setFilterType(FilterType::query()) + $criteria->getSearch()->add( + new Search( + new Property('category_id'), + 't-short', + ), ); - - $criteria->filters()->add(new FilterGroupCollection([ + $criteria->getFilters()->add(new FilterGroupCollection([ new Filter( new Field('price'), FilterOperator::LTE, @@ -403,19 +388,14 @@ class AggsTest extends AbstractTestCase public function testCombineFilter() { $criteria = new Criteria(); - - $criteria->filters()->add( - (new FilterGroupCollection([ - new Filter( - new Field('category_id'), - FilterOperator::EQ, - new FilterKeyword('t-short') - ) - ])) - ->setFilterType(FilterType::query()) + $criteria->getSearch()->add( + new Search( + new Property('category_id'), + 't-short', + ), ); - $criteria->filters()->add(new FilterGroupCollection([ + $criteria->getFilters()->add(new FilterGroupCollection([ new Filter( new Field('color'), FilterOperator::EQ, @@ -423,7 +403,7 @@ class AggsTest extends AbstractTestCase ) ])); - $criteria->filters()->add(new FilterGroupCollection([ + $criteria->getFilters()->add(new FilterGroupCollection([ new Filter( new Field('price'), FilterOperator::LTE, @@ -538,19 +518,14 @@ class AggsTest extends AbstractTestCase public function testCombineFilterTwo() { $criteria = new Criteria(); - - $criteria->filters()->add( - (new FilterGroupCollection([ - new Filter( - new Field('category_id'), - FilterOperator::EQ, - new FilterKeyword('t-short') - ) - ])) - ->setFilterType(FilterType::query()) + $criteria->getSearch()->add( + new Search( + new Property('category_id'), + 't-short', + ), ); - $criteria->filters()->add(new FilterGroupCollection([ + $criteria->getFilters()->add(new FilterGroupCollection([ new Filter( new Field('color'), FilterOperator::EQ, @@ -558,7 +533,7 @@ class AggsTest extends AbstractTestCase ) ])); - $criteria->filters()->add(new FilterGroupCollection([ + $criteria->getFilters()->add(new FilterGroupCollection([ new Filter( new Field('price'), FilterOperator::LTE, @@ -675,19 +650,14 @@ class AggsTest extends AbstractTestCase public function testKeywordFilter() { $criteria = new Criteria(); - - $criteria->filters()->add( - (new FilterGroupCollection([ - new Filter( - new Field('category_id'), - FilterOperator::EQ, - new FilterKeyword('t-short') - ) - ])) - ->setFilterType(FilterType::query()) + $criteria->getSearch()->add( + new Search( + new Property('category_id'), + 't-short', + ), ); - $criteria->filters()->add(new FilterGroupCollection([ + $criteria->getFilters()->add(new FilterGroupCollection([ new Filter( new Field('color'), FilterOperator::EQ, @@ -695,7 +665,7 @@ class AggsTest extends AbstractTestCase ) ])); - $criteria->filters()->add(new FilterGroupCollection([ + $criteria->getFilters()->add(new FilterGroupCollection([ new Filter( new Field('brand'), FilterOperator::EQ, @@ -703,7 +673,7 @@ class AggsTest extends AbstractTestCase ) ])); - $criteria->filters()->add(new FilterGroupCollection([ + $criteria->getFilters()->add(new FilterGroupCollection([ new Filter( new Field('price'), FilterOperator::GT, @@ -711,6 +681,8 @@ class AggsTest extends AbstractTestCase ) ])); + $GLOBALS['DD'] = true; + $q = new SearchQuery($criteria); $handler = SearchClient::getInstance(); @@ -820,19 +792,14 @@ class AggsTest extends AbstractTestCase public function testKeywordFilterTwo() { $criteria = new Criteria(); - - $criteria->filters()->add( - (new FilterGroupCollection([ - new Filter( - new Field('category_id'), - FilterOperator::EQ, - new FilterKeyword('t-short') - ) - ])) - ->setFilterType(FilterType::query()) + $criteria->getSearch()->add( + new Search( + new Property('category_id'), + 't-short', + ), ); - $criteria->filters()->add(new FilterGroupCollection([ + $criteria->getFilters()->add(new FilterGroupCollection([ new Filter( new Field('color'), FilterOperator::EQ, @@ -840,7 +807,7 @@ class AggsTest extends AbstractTestCase ) ])); - $criteria->filters()->add( + $criteria->getFilters()->add( (new FilterGroupCollection([ new Filter( new Field('brand'), diff --git a/tests/Filter/CommonRangeKeywordsTest.php b/tests/Filter/CommonRangeKeywordsTest.php index c0bb4063dca827d5fb5885328386ec4500ec77c8..035dc784e0b1f6cdb826f47d834ede123089960f 100644 --- a/tests/Filter/CommonRangeKeywordsTest.php +++ b/tests/Filter/CommonRangeKeywordsTest.php @@ -3,13 +3,13 @@ namespace IQDEV\ElasticSearchTests\Filter; use IQDEV\ElasticSearch\Criteria; -use IQDEV\ElasticSearch\Filter\Collection\FilterGroupCollection; -use IQDEV\ElasticSearch\Filter\Field; -use IQDEV\ElasticSearch\Filter\Filter; -use IQDEV\ElasticSearch\Filter\FilterOperator; -use IQDEV\ElasticSearch\Filter\Value\FilterKeyword; -use IQDEV\ElasticSearch\Filter\Value\FilterNumber; -use IQDEV\ElasticSearch\Query\SearchQuery; +use IQDEV\ElasticSearch\Request\Filter\Collection\FilterGroupCollection; +use IQDEV\ElasticSearch\Request\Filter\Field; +use IQDEV\ElasticSearch\Request\Filter\Filter; +use IQDEV\ElasticSearch\Request\Filter\FilterOperator; +use IQDEV\ElasticSearch\Request\Filter\Value\FilterKeyword; +use IQDEV\ElasticSearch\Request\Filter\Value\FilterNumber; +use IQDEV\ElasticSearch\Request\Query\SearchQuery; use IQDEV\ElasticSearchTests\AbstractTestCase; use IQDEV\ElasticSearchTests\Helpers\FormatData; use IQDEV\ElasticSearchTests\Service\SearchClient; @@ -25,7 +25,7 @@ class CommonRangeKeywordsTest extends AbstractTestCase { $criteria = new Criteria(); - $criteria->filters()->add(new FilterGroupCollection([ + $criteria->getFilters()->add(new FilterGroupCollection([ new Filter( new Field('color'), FilterOperator::EQ, @@ -33,7 +33,7 @@ class CommonRangeKeywordsTest extends AbstractTestCase ) ])); - $criteria->filters()->add(new FilterGroupCollection([ + $criteria->getFilters()->add(new FilterGroupCollection([ new Filter( new Field('price'), FilterOperator::GT, @@ -65,7 +65,7 @@ class CommonRangeKeywordsTest extends AbstractTestCase { $criteria = new Criteria(); - $criteria->filters()->add(new FilterGroupCollection([ + $criteria->getFilters()->add(new FilterGroupCollection([ new Filter( new Field('color'), FilterOperator::EQ, @@ -73,7 +73,7 @@ class CommonRangeKeywordsTest extends AbstractTestCase ) ])); - $criteria->filters()->add(new FilterGroupCollection([ + $criteria->getFilters()->add(new FilterGroupCollection([ new Filter( new Field('price'), FilterOperator::LT, @@ -105,7 +105,7 @@ class CommonRangeKeywordsTest extends AbstractTestCase { $criteria = new Criteria(); - $criteria->filters()->add(new FilterGroupCollection([ + $criteria->getFilters()->add(new FilterGroupCollection([ new Filter( new Field('color'), FilterOperator::EQ, @@ -113,7 +113,7 @@ class CommonRangeKeywordsTest extends AbstractTestCase ) ])); - $criteria->filters()->add(new FilterGroupCollection([ + $criteria->getFilters()->add(new FilterGroupCollection([ new Filter( new Field('price'), FilterOperator::GTE, diff --git a/tests/Filter/IndexesTest.php b/tests/Filter/IndexesTest.php index 18432b8ca596d1bf291e8781f879a2de321c7a4f..925a071d0fdd96fd86d233c4cbb2d5dae14cba36 100644 --- a/tests/Filter/IndexesTest.php +++ b/tests/Filter/IndexesTest.php @@ -3,6 +3,7 @@ namespace IQDEV\ElasticSearchTests\Filter; use Elastic\Elasticsearch\Client; +use IQDEV\ElasticSearch\Config\Mapping\ProductMapping; use IQDEV\ElasticSearch\Configuration; use IQDEV\ElasticSearch\Converter\EsResponseToResult; use IQDEV\ElasticSearch\Indexer\IndexRunner; @@ -34,7 +35,7 @@ class IndexesTest extends AbstractTestCase { parent::__construct($name, $data, $dataName); - $this->configuration = new ChangingStateConfiguration(); + $this->configuration = new ChangingStateConfiguration(new ProductMapping()); $this->esClient = ClientFactory::create(); $this->indexRunner = new IndexRunner( diff --git a/tests/Filter/KeywordsTest.php b/tests/Filter/KeywordsTest.php index 71d73749bbc86672220f017852dc8d9caa70a857..ff61436121c7f1abe58bb118b5f337eb70155391 100644 --- a/tests/Filter/KeywordsTest.php +++ b/tests/Filter/KeywordsTest.php @@ -3,13 +3,14 @@ namespace IQDEV\ElasticSearchTests\Filter; use IQDEV\ElasticSearch\Criteria; -use IQDEV\ElasticSearch\Filter\Collection\FilterGroupCollection; -use IQDEV\ElasticSearch\Filter\Field; -use IQDEV\ElasticSearch\Filter\Filter; -use IQDEV\ElasticSearch\Filter\FilterOperator; -use IQDEV\ElasticSearch\Filter\FilterType; -use IQDEV\ElasticSearch\Filter\Value\FilterKeyword; -use IQDEV\ElasticSearch\Query\SearchQuery; +use IQDEV\ElasticSearch\Document\Property\Property; +use IQDEV\ElasticSearch\Request\Filter\Collection\FilterGroupCollection; +use IQDEV\ElasticSearch\Request\Filter\Field; +use IQDEV\ElasticSearch\Request\Filter\Filter; +use IQDEV\ElasticSearch\Request\Filter\FilterOperator; +use IQDEV\ElasticSearch\Request\Filter\Value\FilterKeyword; +use IQDEV\ElasticSearch\Request\Query\SearchQuery; +use IQDEV\ElasticSearch\Request\Search\Search; use IQDEV\ElasticSearchTests\AbstractTestCase; use IQDEV\ElasticSearchTests\Helpers\FormatData; use IQDEV\ElasticSearchTests\Service\SearchClient; @@ -25,7 +26,7 @@ class KeywordsTest extends AbstractTestCase { $criteria = new Criteria(); - $criteria->filters()->add(new FilterGroupCollection([ + $criteria->getFilters()->add(new FilterGroupCollection([ new Filter( new Field('color'), FilterOperator::EQ, @@ -55,7 +56,7 @@ class KeywordsTest extends AbstractTestCase { $criteria = new Criteria(); - $criteria->filters()->add(new FilterGroupCollection([ + $criteria->getFilters()->add(new FilterGroupCollection([ new Filter( new Field('color'), FilterOperator::EQ, @@ -87,19 +88,14 @@ class KeywordsTest extends AbstractTestCase public function testExistByFilterAndCategory(): void { $criteria = new Criteria(); - - $criteria->filters()->add( - (new FilterGroupCollection([ - new Filter( - new Field('category_id'), - FilterOperator::EQ, - new FilterKeyword('shoes') - ) - ])) - ->setFilterType(FilterType::query()) + $criteria->getSearch()->add( + new Search( + new Property('category_id'), + 'shoes', + ), ); - $criteria->filters()->add(new FilterGroupCollection([ + $criteria->getFilters()->add(new FilterGroupCollection([ new Filter( new Field('color'), FilterOperator::EQ, @@ -131,7 +127,7 @@ class KeywordsTest extends AbstractTestCase { $criteria = new Criteria(); - $criteria->filters()->add(new FilterGroupCollection([ + $criteria->getFilters()->add(new FilterGroupCollection([ new Filter( new Field('color'), FilterOperator::EQ, @@ -166,7 +162,7 @@ class KeywordsTest extends AbstractTestCase { $criteria = new Criteria(); - $criteria->filters()->add(new FilterGroupCollection([ + $criteria->getFilters()->add(new FilterGroupCollection([ new Filter( new Field('color'), FilterOperator::EQ, @@ -203,18 +199,14 @@ class KeywordsTest extends AbstractTestCase { $criteria = new Criteria(); - $criteria->filters()->add( - (new FilterGroupCollection([ - new Filter( - new Field('category_id'), - FilterOperator::EQ, - new FilterKeyword('prices') - ) - ])) - ->setFilterType(FilterType::query()) + $criteria->getSearch()->add( + new Search( + new Property('category_id'), + 'prices', + ), ); - $criteria->filters()->add(new FilterGroupCollection([ + $criteria->getFilters()->add(new FilterGroupCollection([ new Filter( new Field('color'), FilterOperator::EQ, diff --git a/tests/Filter/QueryAndPostFilterTest.php b/tests/Filter/QueryAndPostFilterTest.php index c2639493925cd4bffef10aa0b560930ac6c3dc65..88f682ac650463c17d60e06206a22e2fe5e661e1 100644 --- a/tests/Filter/QueryAndPostFilterTest.php +++ b/tests/Filter/QueryAndPostFilterTest.php @@ -3,15 +3,15 @@ namespace IQDEV\ElasticSearchTests\Filter; use IQDEV\ElasticSearch\Criteria; -use IQDEV\ElasticSearch\Filter\Collection\FilterGroupCollection; -use IQDEV\ElasticSearch\Filter\Field; -use IQDEV\ElasticSearch\Filter\Filter; -use IQDEV\ElasticSearch\Filter\FilterOperator; -use IQDEV\ElasticSearch\Filter\FilterType; -use IQDEV\ElasticSearch\Filter\LogicOperator; -use IQDEV\ElasticSearch\Filter\Value\FilterKeyword; -use IQDEV\ElasticSearch\Filter\Value\FilterNumber; -use IQDEV\ElasticSearch\Query\SearchQuery; +use IQDEV\ElasticSearch\Request\Filter\Collection\FilterGroupCollection; +use IQDEV\ElasticSearch\Request\Filter\Field; +use IQDEV\ElasticSearch\Request\Filter\Filter; +use IQDEV\ElasticSearch\Request\Filter\FilterOperator; +use IQDEV\ElasticSearch\Request\Filter\FilterType; +use IQDEV\ElasticSearch\Request\Filter\LogicOperator; +use IQDEV\ElasticSearch\Request\Filter\Value\FilterKeyword; +use IQDEV\ElasticSearch\Request\Filter\Value\FilterNumber; +use IQDEV\ElasticSearch\Request\Query\SearchQuery; use IQDEV\ElasticSearchTests\AbstractTestCase; use IQDEV\ElasticSearchTests\Helpers\FormatData; use IQDEV\ElasticSearchTests\Service\SearchClient; @@ -32,8 +32,8 @@ class QueryAndPostFilterTest extends AbstractTestCase new FilterKeyword('not') ) ]); - $filterCollectionBrand->setFilterType(FilterType::query()); - $criteria->filters()->add($filterCollectionBrand); + $filterCollectionBrand->setFilterType(FilterType::QUERY); + $criteria->getFilters()->add($filterCollectionBrand); $q = new SearchQuery($criteria); @@ -63,8 +63,8 @@ class QueryAndPostFilterTest extends AbstractTestCase new FilterKeyword('adidas') ) ]); - $filterCollectionBrand->setFilterType(FilterType::query()); - $criteria->filters()->add($filterCollectionBrand); + $filterCollectionBrand->setFilterType(FilterType::QUERY); + $criteria->getFilters()->add($filterCollectionBrand); $q = new SearchQuery($criteria); @@ -188,8 +188,8 @@ class QueryAndPostFilterTest extends AbstractTestCase ]); $filterCollectionBrand ->setLogicOperator(LogicOperator::OR) - ->setFilterType(FilterType::query()); - $criteria->filters()->add($filterCollectionBrand); + ->setFilterType(FilterType::QUERY); + $criteria->getFilters()->add($filterCollectionBrand); $filterCollectionBrand = new FilterGroupCollection([ new Filter( @@ -198,7 +198,7 @@ class QueryAndPostFilterTest extends AbstractTestCase new FilterKeyword('nike') ), ]); - $criteria->filters()->add($filterCollectionBrand); + $criteria->getFilters()->add($filterCollectionBrand); $q = new SearchQuery($criteria); @@ -348,8 +348,8 @@ class QueryAndPostFilterTest extends AbstractTestCase ]); $filterCollectionBrand ->setLogicOperator(LogicOperator::OR) - ->setFilterType(FilterType::query()); - $criteria->filters()->add($filterCollectionBrand); + ->setFilterType(FilterType::QUERY); + $criteria->getFilters()->add($filterCollectionBrand); $filterCollectionColor = new FilterGroupCollection([ new Filter( @@ -358,7 +358,7 @@ class QueryAndPostFilterTest extends AbstractTestCase new FilterKeyword('white') ), ]); - $criteria->filters()->add($filterCollectionColor); + $criteria->getFilters()->add($filterCollectionColor); $q = new SearchQuery($criteria); @@ -493,8 +493,8 @@ class QueryAndPostFilterTest extends AbstractTestCase ]); $filterCollectionBrand ->setLogicOperator(LogicOperator::OR) - ->setFilterType(FilterType::query()); - $criteria->filters()->add($filterCollectionBrand); + ->setFilterType(FilterType::QUERY); + $criteria->getFilters()->add($filterCollectionBrand); $filterCollectionColor = new FilterGroupCollection([ new Filter( @@ -503,8 +503,8 @@ class QueryAndPostFilterTest extends AbstractTestCase new FilterKeyword('white') ), ]); - $filterCollectionColor->setFilterType(FilterType::query()); - $criteria->filters()->add($filterCollectionColor); + $filterCollectionColor->setFilterType(FilterType::QUERY); + $criteria->getFilters()->add($filterCollectionColor); $filterCollectionBrand = new FilterGroupCollection([ new Filter( @@ -513,7 +513,7 @@ class QueryAndPostFilterTest extends AbstractTestCase new FilterKeyword('nike') ), ]); - $criteria->filters()->add($filterCollectionBrand); + $criteria->getFilters()->add($filterCollectionBrand); $q = new SearchQuery($criteria); @@ -636,8 +636,8 @@ class QueryAndPostFilterTest extends AbstractTestCase ]); $filterCollectionBrand ->setLogicOperator(LogicOperator::OR) - ->setFilterType(FilterType::query()); - $criteria->filters()->add($filterCollectionBrand); + ->setFilterType(FilterType::QUERY); + $criteria->getFilters()->add($filterCollectionBrand); $filterCollectionBrand = new FilterGroupCollection([ @@ -647,7 +647,7 @@ class QueryAndPostFilterTest extends AbstractTestCase new FilterKeyword('nike') ), ]); - $criteria->filters()->add($filterCollectionBrand); + $criteria->getFilters()->add($filterCollectionBrand); $filterCollectionColor = new FilterGroupCollection([ new Filter( @@ -656,9 +656,9 @@ class QueryAndPostFilterTest extends AbstractTestCase new FilterKeyword('red') ), ]); - $criteria->filters()->add($filterCollectionColor); - + $criteria->getFilters()->add($filterCollectionColor); + $GLOBALS['DD'] = false; $q = new SearchQuery($criteria); $handler = SearchClient::getInstance(); $result = $handler->handle($q)->result; @@ -802,8 +802,8 @@ class QueryAndPostFilterTest extends AbstractTestCase new FilterNumber(108) ) ]); - $filterCollectionPrice->setFilterType(FilterType::query()); - $criteria->filters()->add($filterCollectionPrice); + $filterCollectionPrice->setFilterType(FilterType::QUERY); + $criteria->getFilters()->add($filterCollectionPrice); $q = new SearchQuery($criteria); @@ -833,8 +833,8 @@ class QueryAndPostFilterTest extends AbstractTestCase new FilterNumber(105) ) ]); - $filterCollectionPrice->setFilterType(FilterType::query()); - $criteria->filters()->add($filterCollectionPrice); + $filterCollectionPrice->setFilterType(FilterType::QUERY); + $criteria->getFilters()->add($filterCollectionPrice); $q = new SearchQuery($criteria); @@ -957,8 +957,8 @@ class QueryAndPostFilterTest extends AbstractTestCase new FilterKeyword('nike') ), ]); - $filterCollection->setFilterType(FilterType::query()); - $criteria->filters()->add($filterCollection); + $filterCollection->setFilterType(FilterType::QUERY); + $criteria->getFilters()->add($filterCollection); $q = new SearchQuery($criteria); $handler = SearchClient::getInstance(); @@ -1079,8 +1079,8 @@ class QueryAndPostFilterTest extends AbstractTestCase new FilterKeyword('nike') ), ]); - $filterCollection->setFilterType(FilterType::query()); - $criteria->filters()->add($filterCollection); + $filterCollection->setFilterType(FilterType::QUERY); + $criteria->getFilters()->add($filterCollection); $filterCollectionColor = new FilterGroupCollection([ new Filter( @@ -1089,7 +1089,7 @@ class QueryAndPostFilterTest extends AbstractTestCase new FilterKeyword('red') ), ]); - $criteria->filters()->add($filterCollectionColor); + $criteria->getFilters()->add($filterCollectionColor); $q = new SearchQuery($criteria); $handler = SearchClient::getInstance(); @@ -1204,8 +1204,8 @@ class QueryAndPostFilterTest extends AbstractTestCase new FilterNumber(104) ), ]); - $filterCollectionPrice->setFilterType(FilterType::query()); - $criteria->filters()->add($filterCollectionPrice); + $filterCollectionPrice->setFilterType(FilterType::QUERY); + $criteria->getFilters()->add($filterCollectionPrice); $filterCollectionBrand = new FilterGroupCollection([ new Filter( @@ -1221,8 +1221,8 @@ class QueryAndPostFilterTest extends AbstractTestCase ]); $filterCollectionBrand ->setLogicOperator(LogicOperator::OR) - ->setFilterType(FilterType::query()); - $criteria->filters()->add($filterCollectionBrand); + ->setFilterType(FilterType::QUERY); + $criteria->getFilters()->add($filterCollectionBrand); $filterCollectionColor = new FilterGroupCollection([ @@ -1232,7 +1232,7 @@ class QueryAndPostFilterTest extends AbstractTestCase new FilterKeyword('green') ), ]); - $criteria->filters()->add($filterCollectionColor); + $criteria->getFilters()->add($filterCollectionColor); $filterCollectionBrand = new FilterGroupCollection([ new Filter( @@ -1241,7 +1241,7 @@ class QueryAndPostFilterTest extends AbstractTestCase new FilterKeyword('nike') ), ]); - $criteria->filters()->add($filterCollectionBrand); + $criteria->getFilters()->add($filterCollectionBrand); $q = new SearchQuery($criteria); @@ -1375,8 +1375,8 @@ class QueryAndPostFilterTest extends AbstractTestCase new FilterNumber(104) ), ]); - $filterCollectionPrice->setFilterType(FilterType::query()); - $criteria->filters()->add($filterCollectionPrice); + $filterCollectionPrice->setFilterType(FilterType::QUERY); + $criteria->getFilters()->add($filterCollectionPrice); $filterCollectionBrand = new FilterGroupCollection([ new Filter( @@ -1392,8 +1392,8 @@ class QueryAndPostFilterTest extends AbstractTestCase ]); $filterCollectionBrand ->setLogicOperator(LogicOperator::OR) - ->setFilterType(FilterType::query()); - $criteria->filters()->add($filterCollectionBrand); + ->setFilterType(FilterType::QUERY); + $criteria->getFilters()->add($filterCollectionBrand); $filterCollectionPrice = new FilterGroupCollection([ @@ -1403,7 +1403,7 @@ class QueryAndPostFilterTest extends AbstractTestCase new FilterNumber(102) ), ]); - $criteria->filters()->add($filterCollectionPrice); + $criteria->getFilters()->add($filterCollectionPrice); $q = new SearchQuery($criteria); @@ -1538,8 +1538,8 @@ class QueryAndPostFilterTest extends AbstractTestCase new FilterNumber(104) ), ]); - $filterCollectionPrice->setFilterType(FilterType::query()); - $criteria->filters()->add($filterCollectionPrice); + $filterCollectionPrice->setFilterType(FilterType::QUERY); + $criteria->getFilters()->add($filterCollectionPrice); $filterCollectionBrand = new FilterGroupCollection([ new Filter( @@ -1555,8 +1555,8 @@ class QueryAndPostFilterTest extends AbstractTestCase ]); $filterCollectionBrand ->setLogicOperator(LogicOperator::OR) - ->setFilterType(FilterType::query()); - $criteria->filters()->add($filterCollectionBrand); + ->setFilterType(FilterType::QUERY); + $criteria->getFilters()->add($filterCollectionBrand); $filterCollectionPrice = new FilterGroupCollection([ @@ -1566,7 +1566,7 @@ class QueryAndPostFilterTest extends AbstractTestCase new FilterNumber(101) ), ]); - $criteria->filters()->add($filterCollectionPrice); + $criteria->getFilters()->add($filterCollectionPrice); $filterCollectionColor = new FilterGroupCollection([ new Filter( @@ -1575,7 +1575,7 @@ class QueryAndPostFilterTest extends AbstractTestCase new FilterKeyword('green') ), ]); - $criteria->filters()->add($filterCollectionColor); + $criteria->getFilters()->add($filterCollectionColor); $q = new SearchQuery($criteria); diff --git a/tests/Filter/QueryTest.php b/tests/Filter/QueryTest.php index 146fff935549b6710db87a2f4e391f5e9d5895c5..54eac8a468edbc88d42ce29ec2de13f8cfe3073b 100644 --- a/tests/Filter/QueryTest.php +++ b/tests/Filter/QueryTest.php @@ -2,16 +2,21 @@ namespace IQDEV\ElasticSearchTests\Filter; +use IQDEV\ElasticSearch\Config\BaseConfiguration; +use IQDEV\ElasticSearch\Config\Mapping\ProductMapping; use IQDEV\ElasticSearch\Converter\CriteriaToEsRequest; +use IQDEV\ElasticSearch\Converter\CriteriaToRequest; use IQDEV\ElasticSearch\Criteria; -use IQDEV\ElasticSearch\Filter\Collection\FilterGroupCollection; -use IQDEV\ElasticSearch\Filter\Field; -use IQDEV\ElasticSearch\Filter\Filter; -use IQDEV\ElasticSearch\Filter\FilterOperator; -use IQDEV\ElasticSearch\Filter\FilterType; -use IQDEV\ElasticSearch\Filter\Value\FilterKeyword; -use IQDEV\ElasticSearch\Filter\Value\FilterNumber; -use IQDEV\ElasticSearch\Query\SearchQuery; +use IQDEV\ElasticSearch\Document\Property\Property; +use IQDEV\ElasticSearch\Request\Filter\Collection\FilterGroupCollection; +use IQDEV\ElasticSearch\Request\Filter\Field; +use IQDEV\ElasticSearch\Request\Filter\Filter; +use IQDEV\ElasticSearch\Request\Filter\FilterOperator; +use IQDEV\ElasticSearch\Request\Filter\FilterType; +use IQDEV\ElasticSearch\Request\Filter\Value\FilterKeyword; +use IQDEV\ElasticSearch\Request\Filter\Value\FilterNumber; +use IQDEV\ElasticSearch\Request\Query\SearchQuery; +use IQDEV\ElasticSearch\Request\Search\Search; use IQDEV\ElasticSearchTests\AbstractTestCase; use IQDEV\ElasticSearchTests\Helpers\FormatData; use IQDEV\ElasticSearchTests\Service\SearchClient; @@ -23,11 +28,14 @@ class QueryTest extends AbstractTestCase { public function testFilterChangeFromPostToQuery() { - $filter = [ + $search = [ 'category' => [ 'key' => 'category_id', 'value' => 'shoes', ], + ]; + + $filter = [ 'brand' => [ 'key' => 'brand', 'value' => 'nike', @@ -40,17 +48,16 @@ class QueryTest extends AbstractTestCase ]; $criteria = new Criteria(); + $criteria->getSearch()->add( + new Search( + new Property($search['category']['key']), + $search['category']['value'], + ), + ); - - $filterCollectionCategory = new FilterGroupCollection([ - new Filter( - new Field($filter['category']['key']), - FilterOperator::EQ, - new FilterKeyword($filter['category']['value']) - ) - ]); - $filterCollectionCategory->setFilterType(FilterType::query()); - $criteria->filters()->add($filterCollectionCategory); + $filterCollectionCategory = new FilterGroupCollection(); + $filterCollectionCategory->setFilterType(FilterType::QUERY); + $criteria->getFilters()->add($filterCollectionCategory); $filterCollectionBrand = new FilterGroupCollection([ new Filter( @@ -75,22 +82,22 @@ class QueryTest extends AbstractTestCase // Формирование фильтра для post $criteriaPost = clone $criteria; - $criteriaPost->filters()->add(clone $filterCollectionPrice); - $criteriaPost->filters()->add(clone $filterCollectionBrand); + $criteriaPost->getFilters()->add(clone $filterCollectionPrice); + $criteriaPost->getFilters()->add(clone $filterCollectionBrand); // Формирование фильтра для query $criteriaQuery = clone $criteria; - $filterTypeQuery = FilterType::query(); + $filterTypeQuery = FilterType::QUERY; $filterCollectionPrice->setFilterType($filterTypeQuery); $filterCollectionBrand->setFilterType($filterTypeQuery); - $criteriaQuery->filters()->add(clone $filterCollectionPrice); - $criteriaQuery->filters()->add(clone $filterCollectionBrand); + $criteriaQuery->getFilters()->add(clone $filterCollectionPrice); + $criteriaQuery->getFilters()->add(clone $filterCollectionBrand); // Получение классов с данными для запроса в es - $criteriaToEsRequest = new CriteriaToEsRequest(); + $criteriaToEsRequest = new CriteriaToRequest(new BaseConfiguration(new ProductMapping())); $requestPost = $criteriaToEsRequest->fromCriteria($criteriaPost); $requestQuery = $criteriaToEsRequest->fromCriteria($criteriaQuery); @@ -170,7 +177,7 @@ class QueryTest extends AbstractTestCase "must" => [ [ "term" => [ - "category_id" => $filter['category']['value'] + "category_id" => $search['category']['value'] ] ], ] @@ -231,7 +238,7 @@ class QueryTest extends AbstractTestCase new FilterNumber($filter['price']['max']) ), ]); - $criteria->filters()->add($filterCollectionPrice); + $criteria->getFilters()->add($filterCollectionPrice); $filterCollectionQueryPrice = new FilterGroupCollection([ @@ -241,11 +248,11 @@ class QueryTest extends AbstractTestCase new FilterNumber($filter['price']['lower']) ), ]); - $filterCollectionQueryPrice->setFilterType(FilterType::query()); - $criteria->filters()->add($filterCollectionQueryPrice); + $filterCollectionQueryPrice->setFilterType(FilterType::QUERY); + $criteria->getFilters()->add($filterCollectionQueryPrice); - $criteriaToEsRequest = new CriteriaToEsRequest(); + $criteriaToEsRequest = new CriteriaToRequest(new BaseConfiguration(new ProductMapping())); $request = $criteriaToEsRequest->fromCriteria($criteria); @@ -356,7 +363,7 @@ class QueryTest extends AbstractTestCase new FilterNumber($filter['price']['min']) ) ]); - $criteria->filters()->add($filterCollectionPrice); + $criteria->getFilters()->add($filterCollectionPrice); $filterCollectionQueryPrice = new FilterGroupCollection([ @@ -366,8 +373,8 @@ class QueryTest extends AbstractTestCase new FilterNumber($filter['price']['lower']) ), ]); - $filterCollectionQueryPrice->setFilterType(FilterType::query()); - $criteria->filters()->add($filterCollectionQueryPrice); + $filterCollectionQueryPrice->setFilterType(FilterType::QUERY); + $criteria->getFilters()->add($filterCollectionQueryPrice); $q = new SearchQuery($criteria); diff --git a/tests/Filter/RangeTest.php b/tests/Filter/RangeTest.php index b83ba83e7b7b28f42660b7f75380cecc8bf61684..9b7c711f3c97de8b649dc98b507e5512313b9c21 100644 --- a/tests/Filter/RangeTest.php +++ b/tests/Filter/RangeTest.php @@ -3,12 +3,12 @@ namespace IQDEV\ElasticSearchTests\Filter; use IQDEV\ElasticSearch\Criteria; -use IQDEV\ElasticSearch\Filter\Collection\FilterGroupCollection; -use IQDEV\ElasticSearch\Filter\Field; -use IQDEV\ElasticSearch\Filter\Filter; -use IQDEV\ElasticSearch\Filter\FilterOperator; -use IQDEV\ElasticSearch\Filter\Value\FilterNumber; -use IQDEV\ElasticSearch\Query\SearchQuery; +use IQDEV\ElasticSearch\Request\Filter\Collection\FilterGroupCollection; +use IQDEV\ElasticSearch\Request\Filter\Field; +use IQDEV\ElasticSearch\Request\Filter\Filter; +use IQDEV\ElasticSearch\Request\Filter\FilterOperator; +use IQDEV\ElasticSearch\Request\Filter\Value\FilterNumber; +use IQDEV\ElasticSearch\Request\Query\SearchQuery; use IQDEV\ElasticSearchTests\AbstractTestCase; use IQDEV\ElasticSearchTests\Helpers\FormatData; use IQDEV\ElasticSearchTests\Service\SearchClient; @@ -24,7 +24,7 @@ class RangeTest extends AbstractTestCase { $criteria = new Criteria(); - $criteria->filters()->add(new FilterGroupCollection([ + $criteria->getFilters()->add(new FilterGroupCollection([ new Filter( new Field('price'), FilterOperator::GTE, @@ -60,7 +60,7 @@ class RangeTest extends AbstractTestCase { $criteria = new Criteria(); - $criteria->filters()->add(new FilterGroupCollection([ + $criteria->getFilters()->add(new FilterGroupCollection([ new Filter( new Field('price'), FilterOperator::GT, @@ -95,7 +95,7 @@ class RangeTest extends AbstractTestCase { $criteria = new Criteria(); - $criteria->filters()->add(new FilterGroupCollection([ + $criteria->getFilters()->add(new FilterGroupCollection([ new Filter( new Field('price'), FilterOperator::GT, @@ -131,7 +131,7 @@ class RangeTest extends AbstractTestCase { $criteria = new Criteria(); - $criteria->filters()->add(new FilterGroupCollection([ + $criteria->getFilters()->add(new FilterGroupCollection([ new Filter( new Field('price'), FilterOperator::LTE, @@ -165,7 +165,7 @@ class RangeTest extends AbstractTestCase { $criteria = new Criteria(); - $criteria->filters()->add(new FilterGroupCollection([ + $criteria->getFilters()->add(new FilterGroupCollection([ new Filter( new Field('price'), FilterOperator::LT, @@ -199,7 +199,7 @@ class RangeTest extends AbstractTestCase { $criteria = new Criteria(); - $criteria->filters()->add(new FilterGroupCollection([ + $criteria->getFilters()->add(new FilterGroupCollection([ new Filter( new Field('price'), FilterOperator::LT, @@ -232,7 +232,7 @@ class RangeTest extends AbstractTestCase { $criteria = new Criteria(); - $criteria->filters()->add(new FilterGroupCollection([ + $criteria->getFilters()->add(new FilterGroupCollection([ new Filter( new Field('price'), FilterOperator::GTE, @@ -270,7 +270,7 @@ class RangeTest extends AbstractTestCase { $criteria = new Criteria(); - $criteria->filters()->add(new FilterGroupCollection([ + $criteria->getFilters()->add(new FilterGroupCollection([ new Filter( new Field('price'), FilterOperator::GTE, @@ -307,7 +307,7 @@ class RangeTest extends AbstractTestCase { $criteria = new Criteria(); - $criteria->filters()->add(new FilterGroupCollection([ + $criteria->getFilters()->add(new FilterGroupCollection([ new Filter( new Field('price'), FilterOperator::GTE, @@ -344,7 +344,7 @@ class RangeTest extends AbstractTestCase { $criteria = new Criteria(); - $criteria->filters()->add(new FilterGroupCollection([ + $criteria->getFilters()->add(new FilterGroupCollection([ new Filter( new Field('price'), FilterOperator::GTE, diff --git a/tests/Filter/SearchItemsTest.php b/tests/Filter/SearchItemsTest.php index 41745638c34e4bf0746804f22379131fbd70ca40..597c27d1fde62729dd454f422e76ef16d767e7a5 100644 --- a/tests/Filter/SearchItemsTest.php +++ b/tests/Filter/SearchItemsTest.php @@ -3,13 +3,10 @@ namespace IQDEV\ElasticSearchTests\Filter; use IQDEV\ElasticSearch\Criteria; -use IQDEV\ElasticSearch\Filter\Collection\FilterGroupCollection; -use IQDEV\ElasticSearch\Filter\Field; -use IQDEV\ElasticSearch\Filter\Filter; -use IQDEV\ElasticSearch\Filter\FilterOperator; -use IQDEV\ElasticSearch\Filter\FilterType; -use IQDEV\ElasticSearch\Filter\Value\FilterKeyword; -use IQDEV\ElasticSearch\Query\SearchQuery; +use IQDEV\ElasticSearch\Document\Property\Property; +use IQDEV\ElasticSearch\Document\Property\PropertyType; +use IQDEV\ElasticSearch\Request\Query\SearchQuery; +use IQDEV\ElasticSearch\Request\Search\Search; use IQDEV\ElasticSearchTests\AbstractTestCase; use IQDEV\ElasticSearchTests\Helpers\FormatData; use IQDEV\ElasticSearchTests\Service\SearchClient; @@ -24,16 +21,11 @@ class SearchItemsTest extends AbstractTestCase public function testExistByCategory(): void { $criteria = new Criteria(); - - $criteria->filters()->add( - (new FilterGroupCollection([ - new Filter( - new Field('category_id'), - FilterOperator::EQ, - new FilterKeyword('prices') - ) - ])) - ->setFilterType(FilterType::query()) + $criteria->getSearch()->add( + new Search( + new Property('category_id'), + 'prices' + ) ); $q = new SearchQuery($criteria); @@ -60,15 +52,11 @@ class SearchItemsTest extends AbstractTestCase { $criteria = new Criteria(); - $criteria->filters()->add( - (new FilterGroupCollection([ - new Filter( - new Field('category_id'), - FilterOperator::EQ, - new FilterKeyword('') - ) - ])) - ->setFilterType(FilterType::query()) + $criteria->getSearch()->add( + new Search( + new Property('category_id'), + '', + ) ); $q = new SearchQuery($criteria); @@ -124,15 +112,11 @@ class SearchItemsTest extends AbstractTestCase { $criteria = new Criteria(); - $criteria->filters()->add( - (new FilterGroupCollection([ - new Filter( - new Field('search'), - FilterOperator::EQ, - new FilterKeyword('Nike') - ) - ])) - ->setFilterType(FilterType::query()) + $criteria->getSearch()->add( + new Search( + new Property('full_search_content', PropertyType::TEXT), + 'Nike' + ) ); $q = new SearchQuery($criteria); @@ -161,15 +145,11 @@ class SearchItemsTest extends AbstractTestCase { $criteria = new Criteria(); - $criteria->filters()->add( - (new FilterGroupCollection([ - new Filter( - new Field('search'), - FilterOperator::EQ, - new FilterKeyword('Nike Dri-FIT Strike') - ) - ])) - ->setFilterType(FilterType::query()) + $criteria->getSearch()->add( + new Search( + new Property('full_search_content', PropertyType::TEXT), + 'Nike Dri-FIT Strike', + ), ); $q = new SearchQuery($criteria); @@ -198,15 +178,11 @@ class SearchItemsTest extends AbstractTestCase { $criteria = new Criteria(); - $criteria->filters()->add( - (new FilterGroupCollection([ - new Filter( - new Field('search'), - FilterOperator::EQ, - new FilterKeyword('Товар с ценой') - ) - ])) - ->setFilterType(FilterType::query()) + $criteria->getSearch()->add( + new Search( + new Property('full_search_content', PropertyType::TEXT), + 'Товар с ценой', + ), ); $q = new SearchQuery($criteria); @@ -214,7 +190,6 @@ class SearchItemsTest extends AbstractTestCase $handler = SearchClient::getInstance(); $result = $handler->handle($q)->result; - $expected = [ 'hits' => [ 'p1', @@ -223,4 +198,4 @@ class SearchItemsTest extends AbstractTestCase $this->assertEqualsCanonicalizing($expected, FormatData::formatData($result)); } -} \ No newline at end of file +} diff --git a/tests/Filter/SortTest.php b/tests/Filter/SortTest.php index 3ba6b7ff251292d981b689c204b870a72e416f58..24d3359e30e4bf2ab3ebb1c7089be357b3057216 100644 --- a/tests/Filter/SortTest.php +++ b/tests/Filter/SortTest.php @@ -2,15 +2,15 @@ namespace IQDEV\ElasticSearchTests\Filter; +use IQDEV\ElasticSearch\Criteria; use IQDEV\ElasticSearch\Document\Property\Property; -use IQDEV\ElasticSearch\Order\OrderDirection; -use IQDEV\ElasticSearch\Order\OrderFactory; +use IQDEV\ElasticSearch\Document\Property\PropertyType; +use IQDEV\ElasticSearch\Request\Order\OrderDirection; +use IQDEV\ElasticSearch\Request\Order\OrderFactory; +use IQDEV\ElasticSearch\Request\Query\SearchQuery; use IQDEV\ElasticSearchTests\AbstractTestCase; use IQDEV\ElasticSearchTests\Helpers\FormatData; use IQDEV\ElasticSearchTests\Service\SearchClient; -use IQDEV\ElasticSearch\Criteria; -use IQDEV\ElasticSearch\Document\Property\PropertyType; -use IQDEV\ElasticSearch\Query\SearchQuery; class SortTest extends AbstractTestCase { @@ -23,7 +23,7 @@ class SortTest extends AbstractTestCase { $criteria = new Criteria(); - $criteria->sorting()->add( + $criteria->getSorting()->add( OrderFactory::createByProperty(new Property('category_id'), OrderDirection::ASC) ); @@ -58,7 +58,7 @@ class SortTest extends AbstractTestCase { $criteria = new Criteria(); - $criteria->sorting()->add( + $criteria->getSorting()->add( OrderFactory::createByProperty(new Property('category_id'), OrderDirection::DESC) ); @@ -93,7 +93,7 @@ class SortTest extends AbstractTestCase { $criteria = new Criteria(); - $criteria->sorting()->add( + $criteria->getSorting()->add( OrderFactory::createByProperty(new Property('color', PropertyType::KEYWORD), OrderDirection::ASC) ); @@ -128,7 +128,7 @@ class SortTest extends AbstractTestCase { $criteria = new Criteria(); - $criteria->sorting()->add( + $criteria->getSorting()->add( OrderFactory::createByProperty(new Property('color', PropertyType::KEYWORD), OrderDirection::DESC) ); @@ -163,7 +163,7 @@ class SortTest extends AbstractTestCase { $criteria = new Criteria(); - $criteria->sorting()->add( + $criteria->getSorting()->add( OrderFactory::createByProperty(new Property('price', PropertyType::NUMBER), OrderDirection::ASC) ); @@ -198,7 +198,7 @@ class SortTest extends AbstractTestCase { $criteria = new Criteria(); - $criteria->sorting()->add( + $criteria->getSorting()->add( OrderFactory::createByProperty(new Property('price', PropertyType::NUMBER), OrderDirection::DESC) ); @@ -233,7 +233,7 @@ class SortTest extends AbstractTestCase { $criteria = new Criteria(); - $criteria->sorting()->add( + $criteria->getSorting()->add( OrderFactory::createByProperty(new Property('size', PropertyType::KEYWORD), OrderDirection::ASC) ); @@ -268,7 +268,7 @@ class SortTest extends AbstractTestCase { $criteria = new Criteria(); - $criteria->sorting()->add( + $criteria->getSorting()->add( OrderFactory::createByProperty(new Property('size', PropertyType::KEYWORD), OrderDirection::DESC) ); diff --git a/tests/Filter/UpdatedSearchTest.php b/tests/Filter/UpdatedSearchTest.php new file mode 100644 index 0000000000000000000000000000000000000000..6e42b1aba4fef9fc80be4c15185059241c0bde3e --- /dev/null +++ b/tests/Filter/UpdatedSearchTest.php @@ -0,0 +1,229 @@ +getSearch()->add( + new Search( + new Property('brand'), + 'rebook', + ), + ); + + $q = new SearchQuery($criteria); + + $handler = SearchClient::getInstance(); + $result = $handler->handle($q)->result; + + $expected = [ + 'hits' => [ + 's3', + 'h3', + 'p1' + ] + ]; + + $this->assertEqualsCanonicalizing($expected, FormatData::formatData($result)); + } + + /** + * Поиск по nested полю и обычному свойству одноврмененно + * + * @return void + */ + public function testSearchByNestedAndNonNestedProperty(): void + { + $criteria = new Criteria(); + + $criteria->getSearch()->add( + new Search( + new Property('brand'), + 'rebook', + ), + ); + + $criteria->getSearch()->add( + new Search( + new Property('category_id'), + 'prices', + ), + ); + + $q = new SearchQuery($criteria); + + $handler = SearchClient::getInstance(); + $result = $handler->handle($q)->result; + + $expected = [ + 'hits' => [ + 'p1' + ] + ]; + + $this->assertEqualsCanonicalizing($expected, FormatData::formatData($result)); + } + + /** + * Поиск по нескольким nested полям + * + * @return void + */ + public function testSearchByDifferentNestedProperty(): void + { + $criteria = new Criteria(); + + $criteria->getSearch()->add( + new Search( + new Property('brand'), + 'rebook', + ), + ); + + $criteria->getSearch()->add( + new Search( + new Property('color'), + 'white', + ), + ); + + $q = new SearchQuery($criteria); + + $handler = SearchClient::getInstance(); + $result = $handler->handle($q)->result; + + $expected = [ + 'hits' => [ + 'h3', + 'p1' + ] + ]; + + $this->assertEqualsCanonicalizing($expected, FormatData::formatData($result)); + } + + public function testQueryNonNested(): void + { + $criteria = new Criteria(); + + $filterCollection = new FilterGroupCollection([ + new Filter( + new Field('category_id'), + FilterOperator::CONTAINS, + new FilterKeyword('shoes'), + ) + ]); + $criteria->getFilters()->add($filterCollection); + + $q = new SearchQuery($criteria); + + $handler = SearchClient::getInstance(); + $result = $handler->handle($q)->result; + + $expected = [ + 'hits' => [ + 's1', + 's2', + 's3', + 's4', + ] + ]; + + $this->assertEqualsCanonicalizing($expected, FormatData::formatData($result)); + } + + public function testQueryNonNestedMoreLogicOr(): void + { + $criteria = new Criteria(); + + $filterCollection = new FilterGroupCollection([ + new Filter( + new Field('category_id'), + FilterOperator::CONTAINS, + new FilterKeyword('shoes'), + ), + new Filter( + new Field('category_id'), + FilterOperator::CONTAINS, + new FilterKeyword('t-short'), + ), + ]); + $filterCollection->setLogicOperator(LogicOperator::OR); + $criteria->getFilters()->add($filterCollection); + + $q = new SearchQuery($criteria); + + $handler = SearchClient::getInstance(); + $result = $handler->handle($q)->result; + + $expected = [ + 'hits' => [ + 's1', + 's2', + 's3', + 's4', + 'h1', + 'h2', + 'h3', + ] + ]; + + $this->assertEqualsCanonicalizing($expected, FormatData::formatData($result)); + } + + public function testQueryNonNestedMoreLogicAnd(): void + { + $criteria = new Criteria(); + + $filterCollection = new FilterGroupCollection([ + new Filter( + new Field('category_id'), + FilterOperator::CONTAINS, + new FilterKeyword('shoes'), + ), + new Filter( + new Field('category_id'), + FilterOperator::CONTAINS, + new FilterKeyword('t-short'), + ), + ]); + $criteria->getFilters()->add($filterCollection); + + $q = new SearchQuery($criteria); + + $handler = SearchClient::getInstance(); + $result = $handler->handle($q)->result; + + $expected = [ + 'hits' => [ + ] + ]; + + $this->assertEqualsCanonicalizing($expected, FormatData::formatData($result)); + } +} diff --git a/tests/Seed/DefaultSeed.php b/tests/Seed/DefaultSeed.php index fac4092c4f6612825d5397cbde55343c27008c41..d1a200b3c96d92baf83c795b3435dfe23877600e 100644 --- a/tests/Seed/DefaultSeed.php +++ b/tests/Seed/DefaultSeed.php @@ -3,6 +3,7 @@ namespace IQDEV\ElasticSearchTests\Seed; use IQDEV\ElasticSearch\Config\BaseConfiguration; +use IQDEV\ElasticSearch\Config\Mapping\ProductMapping; use IQDEV\ElasticSearch\Configuration; use IQDEV\ElasticSearch\Indexer\IndexRunner; use IQDEV\ElasticSearchTests\Factory\ClientFactory; @@ -17,7 +18,7 @@ class DefaultSeed public function __construct() { - $this->configuration = new BaseConfiguration(); + $this->configuration = new BaseConfiguration(new ProductMapping()); $this->indexRunner = new IndexRunner( ClientFactory::create(), @@ -33,49 +34,57 @@ class DefaultSeed 'id' => 's1', 'name' => 'Кроссовки NMD_R1 Boba Fett Spectoo', 'category' => 'shoes', - 'properties' => ['brand' => 'adidas', 'color' => 'green', 'size' => 46,'price' => 100] + 'properties' => ['brand' => 'adidas', 'color' => 'green', 'size' => 46,'price' => 100], + 'year' => 2014, ], [ 'id' => 's2', 'name' => 'КРОССОВКИ ULTRABOOST 5.0 DNA', 'category' => 'shoes', - 'properties' => ['brand' => 'adidas', 'color' => 'red', 'size' => 47,'price' => 101] + 'properties' => ['brand' => 'adidas', 'color' => 'red', 'size' => 47,'price' => 101], + 'year' => 2023, ], [ 'id' => 's3', 'name' => 'Кроссовки Reebok Royal Techque', 'category' => 'shoes', - 'properties' => ['brand' => 'rebook', 'color' => 'blue', 'size' => 47,'price' => 102] + 'properties' => ['brand' => 'rebook', 'color' => 'blue', 'size' => 47,'price' => 102], + 'year' => 1980, ], [ 'id' => 's4', 'name' => 'Nike Air Zoom Pegasus 39', 'category' => 'shoes', - 'properties' => ['brand' => 'nike', 'color' => 'green', 'size' => 43,'price' => 103] + 'properties' => ['brand' => 'nike', 'color' => 'green', 'size' => 43,'price' => 103], + 'year' => 2014, ], [ 'id' => 'h1', 'name' => 'Nike Dri-FIT Strike', 'category' => 't-short', - 'properties' => ['brand' => 'nike', 'color' => 'red', 'size' => 'xl','price' => 104] + 'properties' => ['brand' => 'nike', 'color' => 'red', 'size' => 'xl','price' => 104], + 'year' => 2010, ], [ 'id' => 'h2', 'name' => 'Nike Dri-FIT Rise 365', 'category' => 't-short', - 'properties' => ['brand' => 'nike', 'color' => 'white', 'size' => 'xxl','price' => 105] + 'properties' => ['brand' => 'nike', 'color' => 'white', 'size' => 'xxl','price' => 105], + 'year' => 2000, ], [ 'id' => 'h3', 'name' => 'Компрессионная Футболка ACTIVCHILL Graphic Move', 'category' => 't-short', - 'properties' => ['brand' => 'rebook', 'color' => 'white', 'size' => 'xl','price' => 106] + 'properties' => ['brand' => 'rebook', 'color' => 'white', 'size' => 'xl','price' => 106], + 'year' => 1990, ], [ 'id' => 'p1', 'name' => 'Товар с ценой', 'category' => 'prices', - 'properties' => ['brand' => 'rebook', 'color' => 'white', 'size' => 'xl','price' => 107] + 'properties' => ['brand' => 'rebook', 'color' => 'white', 'size' => 'xl','price' => 107], + 'year' => 2015, ], ]); diff --git a/tests/Service/SearchClient.php b/tests/Service/SearchClient.php index ea73a5b3d250ad237df890ad3ae252baee250ab2..3bcfbc9d8e091a3ff46b35edccb7c93423dab176 100644 --- a/tests/Service/SearchClient.php +++ b/tests/Service/SearchClient.php @@ -2,10 +2,11 @@ namespace IQDEV\ElasticSearchTests\Service; -use IQDEV\ElasticSearch\SearchService; use IQDEV\ElasticSearch\Config\BaseConfiguration as Configuration; +use IQDEV\ElasticSearch\Config\Mapping\ProductMapping; +use IQDEV\ElasticSearch\Request\Query\SearchQueryHandler; +use IQDEV\ElasticSearch\SearchService; use IQDEV\ElasticSearchTests\Factory\ClientFactory; -use IQDEV\ElasticSearch\Query\SearchQueryHandler; class SearchClient { @@ -19,7 +20,7 @@ class SearchClient static::$oInstance = new SearchQueryHandler( new SearchService( ClientFactory::create(), - new Configuration(), + new Configuration(new ProductMapping()), ) ); }