<commit_before><?php

namespace Elcodi\Store\SearchBundle\Services;

use Elastica\Query\BoolQuery;
use Elastica\Query\Match;
use Elastica\Query\MultiMatch;
use Elastica\Query\Nested;
use Elastica\Query\Range;
use Elastica\Query\Term;
use Elastica\Query\Terms;
use Elastica\Query\Wildcard;
use Elastica\Query\Filtered;
use Elastica\Query\QueryString;
use Elastica\Query;
use Elcodi\Component\Currency\Entity\Money;
use Elcodi\Component\Currency\Services\CurrencyConverter;
use Elcodi\Store\SearchBundle\Services\IStoreSearchService;

/**
 * Defines all the search methods
 */
class StoreSearchService implements IStoreSearchService
{
    private $container;
    private $prefix;
    private $paginator;
    private $itemsPerPage;
    private $currencyConverter;
    private $currencyRepository;
    private $currentCurrency;
    private $defaultCurrency;
    private $categoryDefaultConnector;
    private $productPartialSearch;
    private $categoryPartialSearch;

    public function __construct(
        \Symfony\Component\DependencyInjection\ContainerInterface $container,
        $prefix,
        $itemsPerPage,
        CurrencyConverter $currencyConverter,
        $categoryDefaultConnector,
        $productPartialSearch,
        $categoryPartialSearch
    ) {
        $this->container = $container;
        $this->prefix = $prefix;
        $this->itemsPerPage = $itemsPerPage;
        $this->currencyConverter = $currencyConverter;
        $this->categoryDefaultConnector = $categoryDefaultConnector;
        $this->productPartialSearch = $productPartialSearch;
        $this->categoryPartialSearch = $categoryPartialSearch;

        $this->paginator = $this->container->get('knp_paginator');
        $this->currencyRepository = $this->container->get('elcodi.repository.currency');
        $this->currentCurrency = $this->container->get('elcodi.wrapper.currency')->get();
        $this->defaultCurrency = $this->container->get('elcodi.wrapper.default_currency')->get();
    }

    public function searchProducts($query, $page = 1, $limit = null, array $categories = array(), array $priceRange = array(), $categoryConnector = null)
    {
        if (empty($limit)) {
            $limit = $this->itemsPerPage;
        }

        if (empty($categoryConnector)) {
            $categoryConnector = $this->categoryDefaultConnector;
        }

        $finder = $this->createFinderFor('products');

        //$adapter = $finder->createPaginatorAdapter('*'.$query.'*');
        $productQuery = $this->createQueryForProducts($query, $categories, $priceRange, $categoryConnector);

        // $boolQuery->setSort(array('id' => array('order' => 'asc')));

        $adapter = $finder->createPaginatorAdapter($productQuery);

        return $this->paginator->paginate($adapter, $page, $limit);
    }

    private function createFinderFor($type)
    {
        return $this->container->get('fos_elastica.finder.app.' . $type);
    }

    private function createQueryForProducts($query, array $categories = array(), array $priceRange = array(), $categoryConnector)
    {
        $boolQuery = new BoolQuery();

        $enableQuery = new Term();
        $enableQuery->setTerm('enabled', true);
        $boolQuery->addFilter($enableQuery);

        if (!empty($query)) {
            /*$fieldsBoolQuery = new BoolQuery();

            $nameQuery = new Match('name', $query);
            if ($this->productPartialSearch) {
                $nameQuery = new Wildcard('name', '*' . $query . '*');
            }
            $fieldsBoolQuery->addShould($nameQuery);

            $fieldQuery = new MultiMatch();
            $fieldQuery->setQuery($query);
            $fieldQuery->setFields([
                'shortDescription', 'description',
            ]);

            $fieldsBoolQuery->addShould($fieldQuery);

            $skuQuery = new Match('sku', $query);
            if ($this->productPartialSearch) {
                $skuQuery = new Wildcard('sku', '*' . $query . '*');
            }

            $fieldsBoolQuery->addShould($skuQuery);

            $this->setNestedQueriesForProduct($fieldsBoolQuery, $query);*/
            $queryString = new QueryString('*'.$query.'*');

            $boolQuery->addMust($queryString);
        }

        if (!empty($categories)) {
            $this->setCategoriesQuery($boolQuery, $categories, $categoryConnector);
        }

        if (!empty($priceRange)) {
            $this->setPriceRangeQuery($boolQuery, $priceRange);
        }

        // ordina i risultati della ricerca per principalCategory e per id del prodotto
        //$finalQuery = new Query($boolQuery);
        /*$finalQuery->setSort(array(
            'principalCategory.name' => array('order' => 'asc'), 
            'id' => array('order' => 'asc')
        ));*/

        return $boolQuery;
    }

    /*private function setNestedQueriesForProduct(BoolQuery $boolQuery, $query)
    {
        $categories = new Nested();
        $categories->setPath('categories');

        $categoriesQuery = new BoolQuery();

        $categoryNameQuery = new Wildcard('categories.name', '*' . $query . '*');
        if (!$this->categoryPartialSearch) {
            $categoryNameQuery = new Match('categories.name', $query);
        }
        $categoriesQuery->addShould($categoryNameQuery);

        $categories->setQuery($categoriesQuery);

        $boolQuery->addShould($categories);

        $variants = new Nested();
        $variants->setPath('variants');
        $variantsQuery = new MultiMatch();
        $variantsQuery->setQuery($query);
        $variantsQuery->setFields([
            'variants.shortDescription', 'variants.description',
        ]);<commit_msg>fix on search sorting<commit_after><?php

namespace Elcodi\Store\SearchBundle\Services;

use Elastica\Query\BoolQuery;
use Elastica\Query\Match;
use Elastica\Query\MultiMatch;
use Elastica\Query\Nested;
use Elastica\Query\Range;
use Elastica\Query\Term;
use Elastica\Query\Terms;
use Elastica\Query\Wildcard;
use Elastica\Query\Filtered;
use Elastica\Query\QueryString;
use Elastica\Query;
use Elcodi\Component\Currency\Entity\Money;
use Elcodi\Component\Currency\Services\CurrencyConverter;
use Elcodi\Store\SearchBundle\Services\IStoreSearchService;

/**
 * Defines all the search methods
 */
class StoreSearchService implements IStoreSearchService
{
    private $container;
    private $prefix;
    private $paginator;
    private $itemsPerPage;
    private $currencyConverter;
    private $currencyRepository;
    private $currentCurrency;
    private $defaultCurrency;
    private $categoryDefaultConnector;
    private $productPartialSearch;
    private $categoryPartialSearch;

    public function __construct(
        \Symfony\Component\DependencyInjection\ContainerInterface $container,
        $prefix,
        $itemsPerPage,
        CurrencyConverter $currencyConverter,
        $categoryDefaultConnector,
        $productPartialSearch,
        $categoryPartialSearch
    ) {
        $this->container = $container;
        $this->prefix = $prefix;
        $this->itemsPerPage = $itemsPerPage;
        $this->currencyConverter = $currencyConverter;
        $this->categoryDefaultConnector = $categoryDefaultConnector;
        $this->productPartialSearch = $productPartialSearch;
        $this->categoryPartialSearch = $categoryPartialSearch;

        $this->paginator = $this->container->get('knp_paginator');
        $this->currencyRepository = $this->container->get('elcodi.repository.currency');
        $this->currentCurrency = $this->container->get('elcodi.wrapper.currency')->get();
        $this->defaultCurrency = $this->container->get('elcodi.wrapper.default_currency')->get();
    }

    public function searchProducts($query, $page = 1, $limit = null, array $categories = array(), array $priceRange = array(), $categoryConnector = null)
    {
        if (empty($limit)) {
            $limit = $this->itemsPerPage;
        }

        if (empty($categoryConnector)) {
            $categoryConnector = $this->categoryDefaultConnector;
        }

        $finder = $this->createFinderFor('products');

        //$adapter = $finder->createPaginatorAdapter('*'.$query.'*');
        $productQuery = $this->createQueryForProducts($query, $categories, $priceRange, $categoryConnector);

        // $boolQuery->setSort(array('id' => array('order' => 'asc')));

        $adapter = $finder->createPaginatorAdapter($productQuery);

        return $this->paginator->paginate($adapter, $page, $limit);
    }

    private function createFinderFor($type)
    {
        return $this->container->get('fos_elastica.finder.app.' . $type);
    }

    private function createQueryForProducts($query, array $categories = array(), array $priceRange = array(), $categoryConnector)
    {
        $boolQuery = new BoolQuery();

        $enableQuery = new Term();
        $enableQuery->setTerm('enabled', true);
        $boolQuery->addFilter($enableQuery);

        if (!empty($query)) {
            /*$fieldsBoolQuery = new BoolQuery();

            $nameQuery = new Match('name', $query);
            if ($this->productPartialSearch) {
                $nameQuery = new Wildcard('name', '*' . $query . '*');
            }
            $fieldsBoolQuery->addShould($nameQuery);

            $fieldQuery = new MultiMatch();
            $fieldQuery->setQuery($query);
            $fieldQuery->setFields([
                'shortDescription', 'description',
            ]);

            $fieldsBoolQuery->addShould($fieldQuery);

            $skuQuery = new Match('sku', $query);
            if ($this->productPartialSearch) {
                $skuQuery = new Wildcard('sku', '*' . $query . '*');
            }

            $fieldsBoolQuery->addShould($skuQuery);

            $this->setNestedQueriesForProduct($fieldsBoolQuery, $query);*/
            $queryString = new QueryString('*'.$query.'*');

            $boolQuery->addMust($queryString);
        }

        if (!empty($categories)) {
            $this->setCategoriesQuery($boolQuery, $categories, $categoryConnector);
        }

        if (!empty($priceRange)) {
            $this->setPriceRangeQuery($boolQuery, $priceRange);
        }

        // ordina i risultati della ricerca per principalCategory e per id del prodotto
        $finalQuery = new Query($boolQuery);

        if (empty($query) and !empty($categories)) {
            $finalQuery->setSort(array(
                'principalCategory.name' => array('order' => 'asc'), 
                'id' => array('order' => 'asc')
            ));
        }

        return $finalQuery;
    }

    /*private function setNestedQueriesForProduct(BoolQuery $boolQuery, $query)
    {
        $categories = new Nested();
        $categories->setPath('categories');

        $categoriesQuery = new BoolQuery();

        $categoryNameQuery = new Wildcard('categories.name', '*' . $query . '*');
        if (!$this->categoryPartialSearch) {
            $categoryNameQuery = new Match('categories.name', $query);
        }
        $categoriesQuery->addShould($categoryNameQuery);

        $categories->setQuery($categoriesQuery);

        $boolQuery->addShould($categories);

        $variants = new Nested();
        $variants->setPath('variants');
        $variantsQuery = new MultiMatch();
        $variantsQuery->setQuery($query);
        $variantsQuery->setFields([
            'variants.shortDescription', 'variants.description',
        ]);
{'fraction_non_alphanumeric': 0.13901817862474752, 'fraction_numerical': 0.0001756388864494599, 'mean_word_length': 2.861648016276704, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 123, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '979743', 'n_tokens_mistral': 3129, 'n_tokens_neox': 3074, 'n_words': 551}