Skip to content
Snippets Groups Projects
SearchService.php 5.54 KiB
Newer Older
Pavel's avatar
Pavel committed
<?php

namespace IQDEV\ElasticSearch\Domain;

use IQDEV\ElasticSearch\Search\Aggs\Aggs;
use IQDEV\ElasticSearch\Search\Aggs\AggsKeyWordFacet;
use IQDEV\ElasticSearch\Search\Aggs\AggsNumberFacet;
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 Elastic\Elasticsearch\Client;
use IQDEV\Search\{Filter\Filter,
    Filter\FilterKeyword,
    Filter\FilterCategory,
    Filter\FilterNumber,
    Query as DQuery,
    Result,
    SearchService as DomainSearchService,
    Sorting\SortingFieldPair as DSortingFieldPair,
    Sorting\SortingPropertyKeywordPair as DSortingPropertyKeywordPair,
    Sorting\SortingPropertyNumberPair as DSortingPropertyNumberPair
};
use IQDEV\ElasticSearch\Search\Sorting\SortingCollection;
use IQDEV\ElasticSearch\Search\Sorting\SortingFieldsPair;
use IQDEV\ElasticSearch\Search\Sorting\SortingPropertyKeywordPair;
use IQDEV\ElasticSearch\Search\Sorting\SortingPropertyNumberPair;

final class SearchService implements DomainSearchService
{
    private Client $esClient;
    private string $sIndex;

    public function __construct(Client $esClient, string $sIndex = 'product-test')
    {
        $this->esClient = $esClient;
        $this->sIndex = $sIndex;
    }

    public function search(DQuery $q): Result
    {
        $request       = new Request();
        $commonQuery   = new Query();
        $filterKeyword = new Query();
        $filterNumber  = new Query();

        if ($q->filters) {
            foreach ($q->filters as $filter) {
                /** @var Filter $filter */
                if ($filter instanceof FilterCategory) {
                    $request->getQuery()->must(
                        (new Terms('category_id', $filter->value))
                    );
                    continue;
                }

                if ($filter instanceof FilterNumber) {
                    $oFacet = new FilterNumberFacet($filter->key, $filter->min, $filter->max);
                    $filterNumber->filter($oFacet);
                    $commonQuery->filter($oFacet);
                    continue;
                }

                if ($filter instanceof FilterKeyword) {
                    $oFacet = new FilterKeywordFacet($filter->key, $filter->value);
                    $filterKeyword->filter($oFacet);
                    $commonQuery->filter($oFacet);
                    continue;
                }
            }
        }
        $commonFilter = clone $commonQuery;
        $commonFilter->setType(Query::TYPE_FILTER);

        if ($q->pagination) {
            $request->setPagination(
                new Pagination($q->pagination->limit, $q->pagination->page)
            );
        }
        
        if ($q->sorting && !$q->sorting->isEmpty()) {
            $oSortingCollection = new SortingCollection();
            foreach ($q->sorting as $sorting) {
                if ($sorting instanceof DSortingFieldPair) {
                    $oSortingCollection->add(new SortingFieldsPair($sorting->by, $sorting->direction));
                }

                if ($sorting instanceof DSortingPropertyKeywordPair) {
                    $oSortingCollection->add(new SortingPropertyKeywordPair($sorting->by, $sorting->direction));
                }

                if ($sorting instanceof DSortingPropertyNumberPair) {
                    $oSortingCollection->add(new SortingPropertyNumberPair($sorting->by, $sorting->direction));
                }
            }
            $request->setSorting($oSortingCollection);
        }

        if ($q->query) {
            $request->addMatch('full_search_content', ['query' => $q->query]);
        }

        if ($filterKeyword->isEmpty() === false) {
            $nestedFilterKeyword = new Nested();
            $nestedFilterKeyword->setPath('search_data')
                ->setQuery($filterKeyword);
        }

        if ($filterNumber->isEmpty() === false) {
            $nestedFilterNumber = new Nested();
            $nestedFilterNumber->setPath('search_data')
                ->setQuery($filterNumber);
        }

        if ($commonQuery->isEmpty() === false) {
            $nestedFilter = new Nested();
            $nestedFilter->setPath('search_data')
                ->setQuery($commonQuery);
            
            $request->getPostFilter()->filter($nestedFilter);

            $aggsKeywordFiltered = new Aggs('keyword_facet_filtered');
            $aggsKeywordFiltered->addAggs(AggsKeyWordFacet::create('all_keyword_facet_filtered', 'keyword_facet'))
                ->setQuery($commonFilter);
            $request->getAggs()->add($aggsKeywordFiltered);
            
            $aggsNumberFiltered = new Aggs('number_facet_filtered');
            $aggsNumberFiltered->addAggs(AggsNumberFacet::create('all_number_facet_filtered', 'number_facet'))
                ->setQuery($commonFilter);
            $request->getAggs()->add($aggsNumberFiltered);
        }

        $aggsKeyword = AggsKeyWordFacet::create('keyword_facet', 'keyword_facet');
        $request->getAggs()->add($aggsKeyword);
        $aggsNumber = AggsNumberFacet::create('number_facet', 'number_facet');
        $request->getAggs()->add($aggsNumber);

        $response = $this->esClient->search(
            [
                'index' => $this->sIndex,
                'body' => $request->es(),
            ]
        );


        return SearchResultFactory::createFromResponse($response, $request);
    }
}