Skip to content
FilterQuery.php 4.18 KiB
Newer Older
<?php

declare(strict_types=1);

namespace IQDEV\ElasticSearch\Converter\Request;

use IQDEV\ElasticSearch\Config\MappingValidator;
use IQDEV\ElasticSearch\Configuration;
use IQDEV\ElasticSearch\Converter\Request\Collection\NestedFilterCollection;
use IQDEV\ElasticSearch\Converter\Request\Collection\PropertyFilterCollection;
use IQDEV\ElasticSearch\Converter\Request\Filter\AbstractFilterQuery;
use IQDEV\ElasticSearch\Converter\Request\Filter\NestedFilter;
use IQDEV\ElasticSearch\Converter\Request\Filter\PropertyFilter;
Nikita Chernykh's avatar
Nikita Chernykh committed
use IQDEV\ElasticSearch\Criteria\Filter\Collection\FilterCollection;
use IQDEV\ElasticSearch\Criteria\Filter\Collection\FilterGroupCollection;
use IQDEV\ElasticSearch\Criteria\Filter\Filter;
use IQDEV\ElasticSearch\Search\BoolQuery\Query;
use IQDEV\ElasticSearch\Search\Nested;

class FilterQuery
{
    private Query $query;

    public function __construct(
        private readonly Configuration $configuration,
        private readonly FilterCollection $filterCollection,
Nikita Chernykh's avatar
Nikita Chernykh committed
        private array $exclude = [],
    ) {
        $this->query = new Query();
        $this->convertToQuery();
    }

    private function convertToQuery(): void
    {
        [$propertyFilterCollection, $nestedFilterCollection] = $this->separatePropertyTypes($this->filterCollection);

Nikita Chernykh's avatar
Nikita Chernykh committed
        if (false === $propertyFilterCollection->isEmpty()) {
            $this->fillQuery($propertyFilterCollection, new PropertyFilter());
        }

        if (false === $nestedFilterCollection->isEmpty()) {
            $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
    {
Nikita Chernykh's avatar
Nikita Chernykh committed
        $filters = $filterQuery->getQuery($filterGroup, $this->exclude);
        if ($filters instanceof Query) {
Nikita Chernykh's avatar
Nikita Chernykh committed
            if ($filters->isEmpty()) {
                return;
            }

            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) {
Nikita Chernykh's avatar
Nikita Chernykh committed
            if ($filters->getQuery()->isEmpty()) {
                return;
            }

            $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];
    }
}