Loading src/ElasticSearch/Converter/CriteriaToEsRequest.phpdeleted 100644 → 0 +0 −458 Original line number Diff line number Diff line <?php namespace IQDEV\ElasticSearch\Converter; use IQDEV\ElasticSearch\Filter\PostFilterCollection; use IQDEV\ElasticSearch\Filter\QueryFilterCollection; use IQDEV\ElasticSearch\Order\OrderAscType; use IQDEV\ElasticSearch\Order\OrderDescType; use IQDEV\ElasticSearch\Order\OrderField; use IQDEV\ElasticSearch\Order\OrderKeywordProperty; use IQDEV\ElasticSearch\Order\OrderNumberProperty; 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\Terms; use IQDEV\ElasticSearch\Search\Nested; use IQDEV\ElasticSearch\Search\Pagination; use IQDEV\ElasticSearch\Search\Request; use IQDEV\Search\Criteria; use IQDEV\Search\Document\Property\AttrType; use IQDEV\Search\Document\Property\PropertyType; use IQDEV\Search\FIlter\Filter; use IQDEV\Search\Filter\FilterCollection; use IQDEV\Search\Filter\FilterGroupCollection; use IQDEV\Search\Filter\FilterKeyword; use IQDEV\Search\Filter\FilterNumber; use IQDEV\Search\Filter\FilterOperator; use IQDEV\Search\Filter\FilterType; use IQDEV\Search\Filter\LogicOperator; use IQDEV\Search\Order\Order; use IQDEV\Search\Order\OrderAscType as SOrderAscType; use IQDEV\Search\Order\OrderDescType as SOrderDescType; final class CriteriaToEsRequest { public function fromCriteria(Criteria $criteria): Request { $request = new Request(); $request = $this->pagination($request, $criteria); $request = $this->order($request, $criteria); $request = $this->filter($request, $criteria); $request = $this->aggs($request, $criteria); return $request; } private function pagination(Request $request, Criteria $criteria): Request { $request = clone $request; $request->setPagination(new Pagination($criteria->pagination()->limit, $criteria->pagination()->offset)); return $request; } private function order(Request $request, Criteria $criteria): Request { $request = clone $request; if (true === $criteria->sorting()->isEmpty()) { return $request; } foreach ($criteria->sorting() as $order) { /** @var Order $order */ $direction = null; if ($order->orderType() instanceof SOrderAscType) { $direction = new OrderAscType(); } if ($order->orderType() instanceof SOrderDescType) { $direction = new OrderDescType(); } if ($order->orderBy() instanceof AttrType) { $request->getSort()->add(new OrderField($order->orderBy()->key(), $direction)); } elseif ($order->orderBy() instanceof PropertyType) { if ($order->orderBy()->type() === PropertyType::TYPE_KEYWORD) { $request->getSort()->add(new OrderKeywordProperty($order->orderBy()->key(), $direction)); } elseif ($order->orderBy()->type() === PropertyType::TYPE_NUMBER) { $request->getSort()->add(new OrderNumberProperty($order->orderBy()->key(), $direction)); } } } return $request; } private function filter(Request $request, Criteria $criteria): Request { $request = clone $request; if ($criteria->filters()->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(); if ('search' === $field) { if ($filter->operator()->value() === FilterOperator::CONTAINS) { $request->addMatch( 'suggest_search_content', [ 'query' => $value, ], ); } else { $request->addMatch( 'full_search_content', [ 'query' => $value, ], ); } continue; } if ('category_id' === $field) { $request->getQuery()->must( new Terms('category_id', $filter->value()->value()) ); continue; } } } [$queryFilters, $postFilters] = $this->groupFilters($criteria->filters()); $keywordQueryFilter = $this->getKeywordFilter($queryFilters); $keywordPostFilter = $this->getKeywordFilter($postFilters); if (false === $keywordQueryFilter->isEmpty() || false === $keywordPostFilter->isEmpty()) { $keywordNestedFilter = new Nested(); $keywordNestedFilter->setPath('search_data'); if (false === $keywordQueryFilter->isEmpty()) { $keywordNestedFilterQuery = clone $keywordNestedFilter; $keywordNestedFilterQuery->setQuery($keywordQueryFilter); $request->getQuery()->filter($keywordNestedFilterQuery); } if (false === $keywordPostFilter->isEmpty()) { $keywordNestedFilterPost = clone $keywordNestedFilter; $keywordNestedFilterPost->setQuery($keywordPostFilter); $request->getPostFilter()->filter($keywordNestedFilterPost); } } $numberQueryFilter = $this->getNumberFilter($queryFilters); $numberPostFilter = $this->getNumberFilter($postFilters); if (false === $numberQueryFilter->isEmpty() || false === $numberPostFilter->isEmpty()) { $numberNestedFilter = new Nested(); $numberNestedFilter->setPath('search_data'); if (false === $numberQueryFilter->isEmpty()) { $numberNestedFilterQuery = clone $numberNestedFilter; $numberNestedFilterQuery->setQuery($numberQueryFilter); $request->getQuery()->filter($numberNestedFilterQuery); } if (false === $numberPostFilter->isEmpty()) { $numberNestedFilterPost = clone $numberNestedFilter; $numberNestedFilterPost->setQuery($numberPostFilter); $request->getPostFilter()->filter($numberNestedFilterPost); } } return $request; } private function getNumberFilter(FilterCollection $filterCollection, array $excludeFilter = []): Query { $numberFilter = new Query(); if ($filterCollection->isEmpty()) { return $numberFilter; } $ranges = []; foreach ($filterCollection as $filterGroup) { /** @var FilterGroupCollection $filterGroup */ if ($filterGroup->isEmpty()) { continue; } $group = $filterGroup->getLogicalType()->value() === LogicOperator::OR ? count($ranges) + 1 : 0; if (!isset($ranges[$group])) { $ranges[$group] = []; } foreach ($filterGroup as $filter) { /** @var Filter $filter */ $value = $filter->value()->value(); $field = $filter->field()->value(); if (in_array($field, $excludeFilter, true)) { continue; } if (in_array($filter->operator()->value(), [FilterOperator::LT, FilterOperator::LTE], true)) { $ranges[$group][$field][$filter->operator()->value()] = $value; continue; } if (in_array($filter->operator()->value(), [FilterOperator::GT, FilterOperator::GTE], true)) { $ranges[$group][$field][$filter->operator()->value()] = $value; } } } if (false === empty($ranges)) { foreach ($ranges as $iGroup => $group) { foreach ($group as $field => $range) { $facet = new FilterNumberFacet( $field, $range ); if ($iGroup === 0) { $numberFilter->filter($facet); } else { $numberFilter->should($facet); } } } } return $numberFilter; } private function getKeywordFilter(FilterCollection $filterCollection, array $excludeFilter = []): Query { $keywordFilter = new Query(); if ($filterCollection->isEmpty()) { return $keywordFilter; } foreach ($filterCollection as $filterGroup) { /** @var FilterGroupCollection $filterGroup */ if ($filterGroup->isEmpty()) { continue; } $should = $filterGroup->getLogicalType()->value() === LogicOperator::OR; foreach ($filterGroup as $filter) { /** @var Filter $filter */ $value = $filter->value()->value(); $field = $filter->field()->value(); if (in_array($field, $excludeFilter, true)) { continue; } if (in_array($filter->operator()->value(), [FilterOperator::LT, FilterOperator::LTE], true)) { continue; } if (in_array($filter->operator()->value(), [FilterOperator::GT, FilterOperator::GTE], true)) { continue; } if ('search' === $field) { continue; } if ('category_id' === $field) { continue; } if (is_array($value)) { $value = array_map(static fn($v) => (string)$v, $value); } else { $value = (string)$value; } if ($should) { $keywordFilter->should(new FilterKeywordFacet($field, $value)); } else { $keywordFilter->filter(new FilterKeywordFacet($field, $value)); } } } return $keywordFilter; } private function aggs(Request $request, Criteria $criteria): Request { $request = clone $request; if ($criteria->filters()->isEmpty()) { return $request; } $request->getAggs()->add( AggsFacetTerms::create( 'keyword_facet', 'keyword_facet' ) ); $request->getAggs()->add( AggsFacetStats::create( 'number_facet', 'number_facet' ) ); [$queryFilters, $postFilters] = $this->groupFilters($criteria->filters()); $getKey = static fn(string $type, string $name): string => sprintf('%s_facet_%s', $type, $name); foreach ($postFilters as $filterGroup) { /** @var FilterGroupCollection $filterGroup */ foreach ($filterGroup as $filter) { /** @var Filter $filter */ $field = $filter->field()->value(); if ($filter->value() instanceof FilterNumber) { continue; } if (in_array($filter->operator()->value(), [], true)) { continue; } if ('search' === $field) { continue; } if ('category_id' === $field) { continue; } if ($filter->value() instanceof FilterKeyword) { $aggsFiltered = new Aggs($getKey('keyword', $field)); $aggsFiltered->addAggs( AggsFacetTerms::create( 'agg_special', 'keyword_facet' ) ); $queryKeywordFiltered = new Query(); $keywordFilter = $this->getKeywordFilter($postFilters, [$field]); $numberFilter = $this->getNumberFilter($postFilters); if (false === $keywordFilter->isEmpty()) { $nestedFilterKeyword = new Nested(); $nestedFilterKeyword->setPath('search_data') ->setQuery($keywordFilter); $queryKeywordFiltered->filter($nestedFilterKeyword); } if (false === $numberFilter->isEmpty()) { $nestedFilterNumber = new Nested(); $nestedFilterNumber->setPath('search_data') ->setQuery($numberFilter); $queryKeywordFiltered->filter($nestedFilterNumber); } if ($queryKeywordFiltered->isEmpty() === false) { $aggsFiltered->setQuery($queryKeywordFiltered); } else { $aggsFiltered->setNested((new Nested())->setPath('search_data')); } $request->getAggs()->add($aggsFiltered); } } } $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); } if (false === $numberFilter->isEmpty()) { $nestedFilterNumber = new Nested(); $nestedFilterNumber->setPath('search_data') ->setQuery($numberFilter); $queryKeywordFiltered->filter($nestedFilterNumber); $queryNumberFiltered->filter($nestedFilterNumber); } if (false === $queryKeywordFiltered->isEmpty()) { $aggsKeywordFiltered->setQuery($queryKeywordFiltered); } else { $aggsKeywordFiltered->setNested((new Nested())->setPath('search_data')); } if (false === $queryNumberFiltered->isEmpty()) { $aggsNumberFiltered->setQuery($queryNumberFiltered); } else { $aggsNumberFiltered->setNested((new Nested())->setPath('search_data')); } $request->getAggs() ->add($aggsKeywordFiltered) ->add($aggsNumberFiltered); return $request; } /** * @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; } switch ($filterGroup->getFilterType()->value()) { case FilterType::QUERY: $queryFilters->add($filterGroup); break; case FilterType::POST: $postFilters->add($filterGroup); break; } } return [$queryFilters, $postFilters]; } } src/ElasticSearch/Converter/Request/Aggregation/Aggregation.php 0 → 100644 +53 −0 Original line number Diff line number Diff line <?php declare(strict_types=1); namespace IQDEV\ElasticSearch\Converter\Request\Aggregation; use IQDEV\ElasticSearch\Configuration; use IQDEV\ElasticSearch\Criteria\Criteria; use IQDEV\ElasticSearch\Criteria\Filter\FilterType; use IQDEV\ElasticSearch\Search\Aggs\AggsCollection; use IQDEV\ElasticSearch\Search\Aggs\AggsFacetStats; use IQDEV\ElasticSearch\Search\Aggs\AggsFacetTerms; class Aggregation { public function __construct( private readonly Configuration $configuration, private readonly Criteria $criteria, private readonly AggsCollection $aggregations = new AggsCollection(), ) { $this->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); $filterAggregation = new FilterAggregation($this->configuration, $postFilterCollection); $filterAggregation->updateRequestAggregation($this->aggregations); $fullAggregation = new FullAggregation($this->configuration, $postFilterCollection); $fullAggregation->updateRequestAggregation($this->aggregations); } public function getAggregation(): AggsCollection { return $this->aggregations; } } src/ElasticSearch/Converter/Request/Aggregation/FilterAggregation.php 0 → 100644 +63 −0 Original line number Diff line number Diff line <?php declare(strict_types=1); namespace IQDEV\ElasticSearch\Converter\Request\Aggregation; use IQDEV\ElasticSearch\Configuration; use IQDEV\ElasticSearch\Converter\Request\FilterQuery; use IQDEV\ElasticSearch\Criteria\Filter\Collection\FilterCollection; use IQDEV\ElasticSearch\Criteria\Filter\Collection\FilterGroupCollection; use IQDEV\ElasticSearch\Criteria\Filter\Filter; use IQDEV\ElasticSearch\Search\Aggs\Aggs; use IQDEV\ElasticSearch\Search\Aggs\AggsCollection; use IQDEV\ElasticSearch\Search\Aggs\AggsFacetTerms; use IQDEV\ElasticSearch\Search\Nested; class FilterAggregation { private ?Aggs $aggregation = null; public function __construct( private readonly Configuration $configuration, private readonly FilterCollection $filterCollection, ) { } public function updateRequestAggregation(AggsCollection $original): void { foreach ($this->filterCollection as $filterGroup) { /** @var FilterGroupCollection $filterGroup */ foreach ($filterGroup as $filter) { /** @var Filter $filter */ $field = $filter->field()->value(); $aggregation = new Aggs($this->getKey('keyword', $field)); $aggregation->addAggs( AggsFacetTerms::create( 'agg_special', 'keyword_facet' ) ); $queryFilterBuilder = new FilterQuery($this->configuration, $this->filterCollection, [$field]); $query = $queryFilterBuilder->getQuery(); if (false === $query->isEmpty()) { $aggregation->setQuery($query); } else { $aggregation->setNested((new Nested())->setPath('search_data')); } $original->add($aggregation); } } } private function getKey(string $type, string $name): string { return sprintf('%s_facet_%s', $type, $name); } } src/ElasticSearch/Converter/Request/Aggregation/FullAggregation.php 0 → 100644 +71 −0 Original line number Diff line number Diff line <?php declare(strict_types=1); namespace IQDEV\ElasticSearch\Converter\Request\Aggregation; use IQDEV\ElasticSearch\Configuration; use IQDEV\ElasticSearch\Converter\Request\FilterQuery; use IQDEV\ElasticSearch\Criteria\Filter\Collection\FilterCollection; use IQDEV\ElasticSearch\Search\Aggs\Aggs; use IQDEV\ElasticSearch\Search\Aggs\AggsCollection; use IQDEV\ElasticSearch\Search\Aggs\AggsFacetStats; use IQDEV\ElasticSearch\Search\Aggs\AggsFacetTerms; use IQDEV\ElasticSearch\Search\Nested; class FullAggregation { public function __construct( private readonly Configuration $configuration, private readonly FilterCollection $filterCollection, ) { } public function updateRequestAggregation(AggsCollection $original): void { $keywordQuery = (new FilterQuery($this->configuration, $this->filterCollection->getKeywordFilters()))->getQuery(); $numberQuery = (new FilterQuery($this->configuration, $this->filterCollection->getNumberFilters()))->getQuery(); $aggsKeywordFiltered = new Aggs('keyword_facet_filtered'); $aggsKeywordFiltered->addAggs( AggsFacetTerms::create( 'all_keyword_facet_filtered', 'keyword_facet' ) ); $aggsNumberFiltered = new Aggs('number_facet_filtered'); $aggsNumberFiltered->addAggs( AggsFacetStats::create( 'all_number_facet_filtered', 'number_facet' ) ); if (false === $keywordQuery->getFilter()->isEmpty()) { foreach ($keywordQuery->getFilter() as $item) { $numberQuery->getFilter()->add($item); } } if (false === $numberQuery->getFilter()->isEmpty()) { foreach ($numberQuery->getFilter() as $item) { $keywordQuery->getFilter()->add($item); } } if (false === $keywordQuery->getFilter()->isEmpty()) { $aggsKeywordFiltered->setQuery($keywordQuery); } else { $aggsKeywordFiltered->setNested((new Nested())->setPath('search_data')); } if (false === $numberQuery->getFilter()->isEmpty()) { $aggsNumberFiltered->setQuery($numberQuery); } else { $aggsNumberFiltered->setNested((new Nested())->setPath('search_data')); } $original->add($aggsKeywordFiltered)->add($aggsNumberFiltered); } } src/ElasticSearch/Converter/Request/Collection/NestedFilterCollection.php 0 → 100644 +11 −0 Original line number Diff line number Diff line <?php declare(strict_types=1); namespace IQDEV\ElasticSearch\Converter\Request\Collection; use IQDEV\ElasticSearch\Criteria\Filter\Collection\FilterCollection; class NestedFilterCollection extends FilterCollection { } Loading
src/ElasticSearch/Converter/CriteriaToEsRequest.phpdeleted 100644 → 0 +0 −458 Original line number Diff line number Diff line <?php namespace IQDEV\ElasticSearch\Converter; use IQDEV\ElasticSearch\Filter\PostFilterCollection; use IQDEV\ElasticSearch\Filter\QueryFilterCollection; use IQDEV\ElasticSearch\Order\OrderAscType; use IQDEV\ElasticSearch\Order\OrderDescType; use IQDEV\ElasticSearch\Order\OrderField; use IQDEV\ElasticSearch\Order\OrderKeywordProperty; use IQDEV\ElasticSearch\Order\OrderNumberProperty; 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\Terms; use IQDEV\ElasticSearch\Search\Nested; use IQDEV\ElasticSearch\Search\Pagination; use IQDEV\ElasticSearch\Search\Request; use IQDEV\Search\Criteria; use IQDEV\Search\Document\Property\AttrType; use IQDEV\Search\Document\Property\PropertyType; use IQDEV\Search\FIlter\Filter; use IQDEV\Search\Filter\FilterCollection; use IQDEV\Search\Filter\FilterGroupCollection; use IQDEV\Search\Filter\FilterKeyword; use IQDEV\Search\Filter\FilterNumber; use IQDEV\Search\Filter\FilterOperator; use IQDEV\Search\Filter\FilterType; use IQDEV\Search\Filter\LogicOperator; use IQDEV\Search\Order\Order; use IQDEV\Search\Order\OrderAscType as SOrderAscType; use IQDEV\Search\Order\OrderDescType as SOrderDescType; final class CriteriaToEsRequest { public function fromCriteria(Criteria $criteria): Request { $request = new Request(); $request = $this->pagination($request, $criteria); $request = $this->order($request, $criteria); $request = $this->filter($request, $criteria); $request = $this->aggs($request, $criteria); return $request; } private function pagination(Request $request, Criteria $criteria): Request { $request = clone $request; $request->setPagination(new Pagination($criteria->pagination()->limit, $criteria->pagination()->offset)); return $request; } private function order(Request $request, Criteria $criteria): Request { $request = clone $request; if (true === $criteria->sorting()->isEmpty()) { return $request; } foreach ($criteria->sorting() as $order) { /** @var Order $order */ $direction = null; if ($order->orderType() instanceof SOrderAscType) { $direction = new OrderAscType(); } if ($order->orderType() instanceof SOrderDescType) { $direction = new OrderDescType(); } if ($order->orderBy() instanceof AttrType) { $request->getSort()->add(new OrderField($order->orderBy()->key(), $direction)); } elseif ($order->orderBy() instanceof PropertyType) { if ($order->orderBy()->type() === PropertyType::TYPE_KEYWORD) { $request->getSort()->add(new OrderKeywordProperty($order->orderBy()->key(), $direction)); } elseif ($order->orderBy()->type() === PropertyType::TYPE_NUMBER) { $request->getSort()->add(new OrderNumberProperty($order->orderBy()->key(), $direction)); } } } return $request; } private function filter(Request $request, Criteria $criteria): Request { $request = clone $request; if ($criteria->filters()->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(); if ('search' === $field) { if ($filter->operator()->value() === FilterOperator::CONTAINS) { $request->addMatch( 'suggest_search_content', [ 'query' => $value, ], ); } else { $request->addMatch( 'full_search_content', [ 'query' => $value, ], ); } continue; } if ('category_id' === $field) { $request->getQuery()->must( new Terms('category_id', $filter->value()->value()) ); continue; } } } [$queryFilters, $postFilters] = $this->groupFilters($criteria->filters()); $keywordQueryFilter = $this->getKeywordFilter($queryFilters); $keywordPostFilter = $this->getKeywordFilter($postFilters); if (false === $keywordQueryFilter->isEmpty() || false === $keywordPostFilter->isEmpty()) { $keywordNestedFilter = new Nested(); $keywordNestedFilter->setPath('search_data'); if (false === $keywordQueryFilter->isEmpty()) { $keywordNestedFilterQuery = clone $keywordNestedFilter; $keywordNestedFilterQuery->setQuery($keywordQueryFilter); $request->getQuery()->filter($keywordNestedFilterQuery); } if (false === $keywordPostFilter->isEmpty()) { $keywordNestedFilterPost = clone $keywordNestedFilter; $keywordNestedFilterPost->setQuery($keywordPostFilter); $request->getPostFilter()->filter($keywordNestedFilterPost); } } $numberQueryFilter = $this->getNumberFilter($queryFilters); $numberPostFilter = $this->getNumberFilter($postFilters); if (false === $numberQueryFilter->isEmpty() || false === $numberPostFilter->isEmpty()) { $numberNestedFilter = new Nested(); $numberNestedFilter->setPath('search_data'); if (false === $numberQueryFilter->isEmpty()) { $numberNestedFilterQuery = clone $numberNestedFilter; $numberNestedFilterQuery->setQuery($numberQueryFilter); $request->getQuery()->filter($numberNestedFilterQuery); } if (false === $numberPostFilter->isEmpty()) { $numberNestedFilterPost = clone $numberNestedFilter; $numberNestedFilterPost->setQuery($numberPostFilter); $request->getPostFilter()->filter($numberNestedFilterPost); } } return $request; } private function getNumberFilter(FilterCollection $filterCollection, array $excludeFilter = []): Query { $numberFilter = new Query(); if ($filterCollection->isEmpty()) { return $numberFilter; } $ranges = []; foreach ($filterCollection as $filterGroup) { /** @var FilterGroupCollection $filterGroup */ if ($filterGroup->isEmpty()) { continue; } $group = $filterGroup->getLogicalType()->value() === LogicOperator::OR ? count($ranges) + 1 : 0; if (!isset($ranges[$group])) { $ranges[$group] = []; } foreach ($filterGroup as $filter) { /** @var Filter $filter */ $value = $filter->value()->value(); $field = $filter->field()->value(); if (in_array($field, $excludeFilter, true)) { continue; } if (in_array($filter->operator()->value(), [FilterOperator::LT, FilterOperator::LTE], true)) { $ranges[$group][$field][$filter->operator()->value()] = $value; continue; } if (in_array($filter->operator()->value(), [FilterOperator::GT, FilterOperator::GTE], true)) { $ranges[$group][$field][$filter->operator()->value()] = $value; } } } if (false === empty($ranges)) { foreach ($ranges as $iGroup => $group) { foreach ($group as $field => $range) { $facet = new FilterNumberFacet( $field, $range ); if ($iGroup === 0) { $numberFilter->filter($facet); } else { $numberFilter->should($facet); } } } } return $numberFilter; } private function getKeywordFilter(FilterCollection $filterCollection, array $excludeFilter = []): Query { $keywordFilter = new Query(); if ($filterCollection->isEmpty()) { return $keywordFilter; } foreach ($filterCollection as $filterGroup) { /** @var FilterGroupCollection $filterGroup */ if ($filterGroup->isEmpty()) { continue; } $should = $filterGroup->getLogicalType()->value() === LogicOperator::OR; foreach ($filterGroup as $filter) { /** @var Filter $filter */ $value = $filter->value()->value(); $field = $filter->field()->value(); if (in_array($field, $excludeFilter, true)) { continue; } if (in_array($filter->operator()->value(), [FilterOperator::LT, FilterOperator::LTE], true)) { continue; } if (in_array($filter->operator()->value(), [FilterOperator::GT, FilterOperator::GTE], true)) { continue; } if ('search' === $field) { continue; } if ('category_id' === $field) { continue; } if (is_array($value)) { $value = array_map(static fn($v) => (string)$v, $value); } else { $value = (string)$value; } if ($should) { $keywordFilter->should(new FilterKeywordFacet($field, $value)); } else { $keywordFilter->filter(new FilterKeywordFacet($field, $value)); } } } return $keywordFilter; } private function aggs(Request $request, Criteria $criteria): Request { $request = clone $request; if ($criteria->filters()->isEmpty()) { return $request; } $request->getAggs()->add( AggsFacetTerms::create( 'keyword_facet', 'keyword_facet' ) ); $request->getAggs()->add( AggsFacetStats::create( 'number_facet', 'number_facet' ) ); [$queryFilters, $postFilters] = $this->groupFilters($criteria->filters()); $getKey = static fn(string $type, string $name): string => sprintf('%s_facet_%s', $type, $name); foreach ($postFilters as $filterGroup) { /** @var FilterGroupCollection $filterGroup */ foreach ($filterGroup as $filter) { /** @var Filter $filter */ $field = $filter->field()->value(); if ($filter->value() instanceof FilterNumber) { continue; } if (in_array($filter->operator()->value(), [], true)) { continue; } if ('search' === $field) { continue; } if ('category_id' === $field) { continue; } if ($filter->value() instanceof FilterKeyword) { $aggsFiltered = new Aggs($getKey('keyword', $field)); $aggsFiltered->addAggs( AggsFacetTerms::create( 'agg_special', 'keyword_facet' ) ); $queryKeywordFiltered = new Query(); $keywordFilter = $this->getKeywordFilter($postFilters, [$field]); $numberFilter = $this->getNumberFilter($postFilters); if (false === $keywordFilter->isEmpty()) { $nestedFilterKeyword = new Nested(); $nestedFilterKeyword->setPath('search_data') ->setQuery($keywordFilter); $queryKeywordFiltered->filter($nestedFilterKeyword); } if (false === $numberFilter->isEmpty()) { $nestedFilterNumber = new Nested(); $nestedFilterNumber->setPath('search_data') ->setQuery($numberFilter); $queryKeywordFiltered->filter($nestedFilterNumber); } if ($queryKeywordFiltered->isEmpty() === false) { $aggsFiltered->setQuery($queryKeywordFiltered); } else { $aggsFiltered->setNested((new Nested())->setPath('search_data')); } $request->getAggs()->add($aggsFiltered); } } } $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); } if (false === $numberFilter->isEmpty()) { $nestedFilterNumber = new Nested(); $nestedFilterNumber->setPath('search_data') ->setQuery($numberFilter); $queryKeywordFiltered->filter($nestedFilterNumber); $queryNumberFiltered->filter($nestedFilterNumber); } if (false === $queryKeywordFiltered->isEmpty()) { $aggsKeywordFiltered->setQuery($queryKeywordFiltered); } else { $aggsKeywordFiltered->setNested((new Nested())->setPath('search_data')); } if (false === $queryNumberFiltered->isEmpty()) { $aggsNumberFiltered->setQuery($queryNumberFiltered); } else { $aggsNumberFiltered->setNested((new Nested())->setPath('search_data')); } $request->getAggs() ->add($aggsKeywordFiltered) ->add($aggsNumberFiltered); return $request; } /** * @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; } switch ($filterGroup->getFilterType()->value()) { case FilterType::QUERY: $queryFilters->add($filterGroup); break; case FilterType::POST: $postFilters->add($filterGroup); break; } } return [$queryFilters, $postFilters]; } }
src/ElasticSearch/Converter/Request/Aggregation/Aggregation.php 0 → 100644 +53 −0 Original line number Diff line number Diff line <?php declare(strict_types=1); namespace IQDEV\ElasticSearch\Converter\Request\Aggregation; use IQDEV\ElasticSearch\Configuration; use IQDEV\ElasticSearch\Criteria\Criteria; use IQDEV\ElasticSearch\Criteria\Filter\FilterType; use IQDEV\ElasticSearch\Search\Aggs\AggsCollection; use IQDEV\ElasticSearch\Search\Aggs\AggsFacetStats; use IQDEV\ElasticSearch\Search\Aggs\AggsFacetTerms; class Aggregation { public function __construct( private readonly Configuration $configuration, private readonly Criteria $criteria, private readonly AggsCollection $aggregations = new AggsCollection(), ) { $this->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); $filterAggregation = new FilterAggregation($this->configuration, $postFilterCollection); $filterAggregation->updateRequestAggregation($this->aggregations); $fullAggregation = new FullAggregation($this->configuration, $postFilterCollection); $fullAggregation->updateRequestAggregation($this->aggregations); } public function getAggregation(): AggsCollection { return $this->aggregations; } }
src/ElasticSearch/Converter/Request/Aggregation/FilterAggregation.php 0 → 100644 +63 −0 Original line number Diff line number Diff line <?php declare(strict_types=1); namespace IQDEV\ElasticSearch\Converter\Request\Aggregation; use IQDEV\ElasticSearch\Configuration; use IQDEV\ElasticSearch\Converter\Request\FilterQuery; use IQDEV\ElasticSearch\Criteria\Filter\Collection\FilterCollection; use IQDEV\ElasticSearch\Criteria\Filter\Collection\FilterGroupCollection; use IQDEV\ElasticSearch\Criteria\Filter\Filter; use IQDEV\ElasticSearch\Search\Aggs\Aggs; use IQDEV\ElasticSearch\Search\Aggs\AggsCollection; use IQDEV\ElasticSearch\Search\Aggs\AggsFacetTerms; use IQDEV\ElasticSearch\Search\Nested; class FilterAggregation { private ?Aggs $aggregation = null; public function __construct( private readonly Configuration $configuration, private readonly FilterCollection $filterCollection, ) { } public function updateRequestAggregation(AggsCollection $original): void { foreach ($this->filterCollection as $filterGroup) { /** @var FilterGroupCollection $filterGroup */ foreach ($filterGroup as $filter) { /** @var Filter $filter */ $field = $filter->field()->value(); $aggregation = new Aggs($this->getKey('keyword', $field)); $aggregation->addAggs( AggsFacetTerms::create( 'agg_special', 'keyword_facet' ) ); $queryFilterBuilder = new FilterQuery($this->configuration, $this->filterCollection, [$field]); $query = $queryFilterBuilder->getQuery(); if (false === $query->isEmpty()) { $aggregation->setQuery($query); } else { $aggregation->setNested((new Nested())->setPath('search_data')); } $original->add($aggregation); } } } private function getKey(string $type, string $name): string { return sprintf('%s_facet_%s', $type, $name); } }
src/ElasticSearch/Converter/Request/Aggregation/FullAggregation.php 0 → 100644 +71 −0 Original line number Diff line number Diff line <?php declare(strict_types=1); namespace IQDEV\ElasticSearch\Converter\Request\Aggregation; use IQDEV\ElasticSearch\Configuration; use IQDEV\ElasticSearch\Converter\Request\FilterQuery; use IQDEV\ElasticSearch\Criteria\Filter\Collection\FilterCollection; use IQDEV\ElasticSearch\Search\Aggs\Aggs; use IQDEV\ElasticSearch\Search\Aggs\AggsCollection; use IQDEV\ElasticSearch\Search\Aggs\AggsFacetStats; use IQDEV\ElasticSearch\Search\Aggs\AggsFacetTerms; use IQDEV\ElasticSearch\Search\Nested; class FullAggregation { public function __construct( private readonly Configuration $configuration, private readonly FilterCollection $filterCollection, ) { } public function updateRequestAggregation(AggsCollection $original): void { $keywordQuery = (new FilterQuery($this->configuration, $this->filterCollection->getKeywordFilters()))->getQuery(); $numberQuery = (new FilterQuery($this->configuration, $this->filterCollection->getNumberFilters()))->getQuery(); $aggsKeywordFiltered = new Aggs('keyword_facet_filtered'); $aggsKeywordFiltered->addAggs( AggsFacetTerms::create( 'all_keyword_facet_filtered', 'keyword_facet' ) ); $aggsNumberFiltered = new Aggs('number_facet_filtered'); $aggsNumberFiltered->addAggs( AggsFacetStats::create( 'all_number_facet_filtered', 'number_facet' ) ); if (false === $keywordQuery->getFilter()->isEmpty()) { foreach ($keywordQuery->getFilter() as $item) { $numberQuery->getFilter()->add($item); } } if (false === $numberQuery->getFilter()->isEmpty()) { foreach ($numberQuery->getFilter() as $item) { $keywordQuery->getFilter()->add($item); } } if (false === $keywordQuery->getFilter()->isEmpty()) { $aggsKeywordFiltered->setQuery($keywordQuery); } else { $aggsKeywordFiltered->setNested((new Nested())->setPath('search_data')); } if (false === $numberQuery->getFilter()->isEmpty()) { $aggsNumberFiltered->setQuery($numberQuery); } else { $aggsNumberFiltered->setNested((new Nested())->setPath('search_data')); } $original->add($aggsKeywordFiltered)->add($aggsNumberFiltered); } }
src/ElasticSearch/Converter/Request/Collection/NestedFilterCollection.php 0 → 100644 +11 −0 Original line number Diff line number Diff line <?php declare(strict_types=1); namespace IQDEV\ElasticSearch\Converter\Request\Collection; use IQDEV\ElasticSearch\Criteria\Filter\Collection\FilterCollection; class NestedFilterCollection extends FilterCollection { }