Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
No results found
Show changes
Showing
with 5622 additions and 0 deletions
<?php
namespace IQDEV\ElasticSearch;
use IQDEV\ElasticSearch\Criteria\Criteria;
interface Searchable
{
/**
* @param Criteria $criteria
*
* @return Result
*/
public function search(Criteria $criteria): Result;
}
<?php
namespace IQDEV\ElasticSearchTests;
use IQDEV\ElasticSearchTests\Helpers\Arr;
use PHPUnit\Framework\TestCase;
abstract class AbstractTestCase extends TestCase
{
/**
* Частичное сравнение массивов
* @param array $expected
* @param array $actual массив который должен иметь структуру и значения $expected
* @param string $message
* @return void
*/
protected function assertArray(array $expected, array $actual, string $message = '')
{
$expectedKeys = Arr::dot($expected);
$actualKeys = Arr::dot($actual);
foreach ($expectedKeys as $key => $value) {
$this->assertArrayHasKey($key, $actualKeys, $message);
if (isset($actualKeys[$key])) {
$this->assertEquals($actualKeys[$key], $value, $key);
}
}
}
}
\ No newline at end of file
<?php
include_once __DIR__ . '/../bootstrap.php';
$oSeeder = new \IQDEV\ElasticSearchTests\Seed\DefaultSeed();
$oSeeder->start();
\ No newline at end of file
<?php
namespace IQDEV\ElasticSearchTests\Config;
use IQDEV\ElasticSearch\Config\BaseConfiguration;
class ChangingStateConfiguration extends BaseConfiguration
{
public function getIndexName(): string
{
return $_ENV['IQ_ES_PRODUCT_SEARCH_INDEX'] . '_changing-state';
}
}
\ No newline at end of file
<?php
namespace IQDEV\ElasticSearchTests\Factory;
use Elastic\Elasticsearch\Client;
use Elastic\Elasticsearch\ClientBuilder;
class ClientFactory
{
private static $instance = null;
public static function create(): Client
{
if (self::$instance !== null) {
return self::$instance;
}
self::$instance = ClientBuilder::create()
->setHosts(explode(',', $_ENV['IQ_ES_HOSTS'] ?: 'http://localhost:9200'))
->setBasicAuthentication($_ENV['IQ_ES_USER'], $_ENV['IQ_ES_PASSWORD'])
->build();
return self::$instance;
}
}
\ No newline at end of file
<?php
namespace IQDEV\ElasticSearchTests\Filter;
use IQDEV\ElasticSearch\Criteria\Aggs\Aggs;
use IQDEV\ElasticSearch\Criteria\Criteria;
use IQDEV\ElasticSearch\Criteria\Filter\Collection\FilterGroupCollection;
use IQDEV\ElasticSearch\Criteria\Filter\Field;
use IQDEV\ElasticSearch\Criteria\Filter\Filter;
use IQDEV\ElasticSearch\Criteria\Filter\FilterOperator;
use IQDEV\ElasticSearch\Criteria\Filter\Value\FilterNumber;
use IQDEV\ElasticSearch\Criteria\Query\SearchQuery;
use IQDEV\ElasticSearch\Document\Property\Property;
use IQDEV\ElasticSearchTests\AbstractTestCase;
use IQDEV\ElasticSearchTests\Helpers\FormatData;
use IQDEV\ElasticSearchTests\Service\SearchClient;
/**
* Тестирование агрегирующих функций для прямых свойств документов
*/
class AggsPropsTest extends AbstractTestCase
{
public function testCategoryAggs()
{
$criteria = new Criteria();
$criteria->getAggs()->add(
new Aggs(
new Property('new')
)
);
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => [
'h1',
'h2',
'h3',
'p1',
's1',
's2',
's3',
's4',
],
'facets' => [
0 => [
'code' => 'new',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => 0,
'count' => 3,
'active' => true
],
1 => [
'label' => null,
'value' => 1,
'count' => 5,
'active' => true
]
],
'range' => []
]
],
]
];
$this->assertEqualsCanonicalizing($expected, FormatData::formatDataWFacets($result));
}
public function testCategoryAggsWFilters()
{
$criteria = new Criteria();
$criteria->getAggs()->add(
new Aggs(
new Property('new')
)
);
$criteria->getAggs()->add(
new Aggs(
new Property('rating')
)
);
$filterCollectionPrice = new FilterGroupCollection([
new Filter(
new Field('price'),
FilterOperator::GTE,
new FilterNumber(105)
)
]);
$criteria->getFilters()->add($filterCollectionPrice);
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => [
'h2',
'h3',
'p1'
],
'facets' => [
0 => [
'code' => 'brand',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => 'adidas',
'count' => 0,
'active' => false
],
1 => [
'label' => null,
'value' => 'nike',
'count' => 1,
'active' => true
],
3 => [
'label' => null,
'value' => 'rebook',
'count' => 2,
'active' => true
]
],
'range' => []
]
],
1 => [
'code' => 'color',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => 'blue',
'count' => 0,
'active' => false
],
1 => [
'label' => null,
'value' => 'green',
'count' => 0,
'active' => false
],
2 => [
'label' => null,
'value' => 'red',
'count' => 0,
'active' => false
],
3 => [
'label' => null,
'value' => 'white',
'count' => 3,
'active' => true
]
],
'range' => []
]
],
2 => [
'code' => 'size',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
"label" => null,
"value" => "43",
"count" => 0,
"active" => false
],
1 => [
"label" => null,
"value" => "46",
"count" => 0,
"active" => false
],
2 => [
"label" => null,
"value" => "47",
"count" => 0,
"active" => false
],
3 => [
"label" => null,
"value" => "xl",
"count" => 2,
"active" => true
],
4 => [
"label" => null,
"value" => "xxl",
"count" => 1,
"active" => true
],
],
'range' => []
]
],
3 => [
'code' => 'price',
'label' => null,
'type' => 'range',
'items' => [
'list' => [],
'range' => [
0 => [
'label' => null,
'count' => 3,
'active' => true,
'fullRange' => [
'min' => 100.0,
'max' => 107.0
],
'activeRange' => [
'min' => 105.0,
'max' => 107.0
]
]
]
],
],
4 => [
'code' => 'new',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => "0",
'count' => 1,
'active' => true
],
1 => [
'label' => null,
'value' => "1",
'count' => 2,
'active' => true
]
],
'range' => []
]
],
5 => [
'code' => 'rating',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => "3",
'count' => 3,
'active' => true
],
],
'range' => []
]
],
]
];
$this->assertEqualsCanonicalizing($expected, FormatData::formatDataWFacets($result));
}
}
<?php
namespace IQDEV\ElasticSearchTests\Filter;
use IQDEV\ElasticSearch\Criteria\Criteria;
use IQDEV\ElasticSearch\Criteria\Filter\Collection\FilterGroupCollection;
use IQDEV\ElasticSearch\Criteria\Filter\Field;
use IQDEV\ElasticSearch\Criteria\Filter\Filter;
use IQDEV\ElasticSearch\Criteria\Filter\FilterOperator;
use IQDEV\ElasticSearch\Criteria\Filter\LogicOperator;
use IQDEV\ElasticSearch\Criteria\Filter\Value\FilterKeyword;
use IQDEV\ElasticSearch\Criteria\Filter\Value\FilterNumber;
use IQDEV\ElasticSearch\Criteria\Query\SearchQuery;
use IQDEV\ElasticSearch\Criteria\Search\Search;
use IQDEV\ElasticSearch\Document\Property\Property;
use IQDEV\ElasticSearchTests\AbstractTestCase;
use IQDEV\ElasticSearchTests\Helpers\FormatData;
use IQDEV\ElasticSearchTests\Service\SearchClient;
/**
* Тестирование агрегирующих функций
*/
class AggsTest extends AbstractTestCase
{
public function testEmptyFilterByCategory()
{
$criteria = new Criteria();
$criteria->getSearch()->add(
new Search(
new Property('category_id'),
't-short',
),
);
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => [
'h1',
'h2',
'h3'
],
'facets' => [
0 => [
'code' => 'brand',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => 'nike',
'count' => 2,
'active' => true
],
1 => [
'label' => null,
'value' => 'rebook',
'count' => 1,
'active' => true
]
],
'range' => []
]
],
1 => [
'code' => 'color',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => 'red',
'count' => 1,
'active' => true
],
1 => [
'label' => null,
'value' => 'white',
'count' => 2,
'active' => true
]
],
'range' => []
]
],
2 => [
'code' => 'size',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => 'xl',
'count' => 2,
'active' => true
],
1 => [
'label' => null,
'value' => 'xxl',
'count' => 1,
'active' => true
]
],
'range' => []
]
],
3 => [
'code' => 'price',
'label' => null,
'type' => 'range',
'items' => [
'list' => [],
'range' => [
0 => [
'label' => null,
'count' => 3,
'active' => true,
'fullRange' => [
'min' => 104.0,
'max' => 106.0
],
'activeRange' => [
'min' => 104.0,
'max' => 106.0
]
]
]
]
]
]
];
$this->assertEqualsCanonicalizing($expected, FormatData::formatDataWFacets($result));
}
public function testEmptyKeywordFilter()
{
$criteria = new Criteria();
$criteria->getSearch()->add(
new Search(
new Property('category_id'),
't-short',
),
);
$criteria->getFilters()->add(new FilterGroupCollection([
new Filter(
new Field('color'),
FilterOperator::EQ,
new FilterKeyword('white')
)
]));
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => [
'h2',
'h3'
],
'facets' => [
0 => [
'code' => 'brand',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => 'nike',
'count' => 1,
'active' => true
],
1 => [
'label' => null,
'value' => 'rebook',
'count' => 1,
'active' => true
]
],
'range' => []
]
],
1 => [
'code' => 'color',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => 'red',
'count' => 1,
'active' => true
],
1 => [
'label' => null,
'value' => 'white',
'count' => 2,
'active' => true
]
],
'range' => []
]
],
2 => [
'code' => 'size',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => 'xl',
'count' => 1,
'active' => true
],
1 => [
'label' => null,
'value' => 'xxl',
'count' => 1,
'active' => true
]
],
'range' => []
]
],
3 => [
'code' => 'price',
'label' => null,
'type' => 'range',
'items' => [
'list' => [],
'range' => [
0 => [
'label' => null,
'count' => 2,
'active' => true,
'fullRange' => [
'min' => 104.0,
'max' => 106.0
],
'activeRange' => [
'min' => 105.0,
'max' => 106.0
]
]
]
]
]
]
];
$this->assertEqualsCanonicalizing($expected, FormatData::formatDataWFacets($result));
}
public function testRangeFilter()
{
$criteria = new Criteria();
$criteria->getSearch()->add(
new Search(
new Property('category_id'),
't-short',
),
);
$criteria->getFilters()->add(new FilterGroupCollection([
new Filter(
new Field('price'),
FilterOperator::LTE,
new FilterNumber(104.50)
)
]));
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => [
'h1',
],
'facets' => [
0 => [
'code' => 'brand',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => 'nike',
'count' => 1,
'active' => true
],
1 => [
'label' => null,
'value' => 'rebook',
'count' => 0,
'active' => false
]
],
'range' => []
]
],
1 => [
'code' => 'color',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => 'red',
'count' => 1,
'active' => true
],
1 => [
'label' => null,
'value' => 'white',
'count' => 0,
'active' => false
]
],
'range' => []
]
],
2 => [
'code' => 'size',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => 'xl',
'count' => 1,
'active' => true
],
1 => [
'label' => null,
'value' => 'xxl',
'count' => 0,
'active' => false
]
],
'range' => []
]
],
3 => [
'code' => 'price',
'label' => null,
'type' => 'range',
'items' => [
'list' => [],
'range' => [
0 => [
'label' => null,
'count' => 1,
'active' => true,
'fullRange' => [
'min' => 104.0,
'max' => 106.0
],
'activeRange' => [
'min' => 104.0,
'max' => 104.0
]
]
]
]
]
]
];
$this->assertEqualsCanonicalizing($expected, FormatData::formatDataWFacets($result));
}
public function testCombineFilter()
{
$criteria = new Criteria();
$criteria->getSearch()->add(
new Search(
new Property('category_id'),
't-short',
),
);
$criteria->getFilters()->add(new FilterGroupCollection([
new Filter(
new Field('color'),
FilterOperator::EQ,
new FilterKeyword('black')
)
]));
$criteria->getFilters()->add(new FilterGroupCollection([
new Filter(
new Field('price'),
FilterOperator::LTE,
new FilterNumber(104)
)
]));
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => [],
'facets' => [
0 => [
'code' => 'brand',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => 'nike',
'count' => 0,
'active' => false
],
1 => [
'label' => null,
'value' => 'rebook',
'count' => 0,
'active' => false
]
],
'range' => []
]
],
1 => [
'code' => 'color',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => 'red',
'count' => 1,
'active' => true
],
1 => [
'label' => null,
'value' => 'white',
'count' => 0,
'active' => false
]
],
'range' => []
]
],
2 => [
'code' => 'size',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => 'xl',
'count' => 0,
'active' => false
],
1 => [
'label' => null,
'value' => 'xxl',
'count' => 0,
'active' => false
]
],
'range' => []
]
],
3 => [
'code' => 'price',
'label' => null,
'type' => 'range',
'items' => [
'list' => [],
'range' => [
0 => [
'label' => null,
'count' => 0,
'active' => false,
'fullRange' => [
'min' => 104.0,
'max' => 106.0
],
'activeRange' => [
'min' => null,
'max' => null
]
]
]
]
]
]
];
$this->assertEqualsCanonicalizing($expected, FormatData::formatDataWFacets($result));
}
public function testCombineFilterTwo()
{
$criteria = new Criteria();
$criteria->getSearch()->add(
new Search(
new Property('category_id'),
't-short',
),
);
$criteria->getFilters()->add(new FilterGroupCollection([
new Filter(
new Field('color'),
FilterOperator::EQ,
new FilterKeyword('red')
)
]));
$criteria->getFilters()->add(new FilterGroupCollection([
new Filter(
new Field('price'),
FilterOperator::LTE,
new FilterNumber(105)
)
]));
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => [
'h1'
],
'facets' => [
0 => [
'code' => 'brand',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => 'nike',
'count' => 1,
'active' => true
],
1 => [
'label' => null,
'value' => 'rebook',
'count' => 0,
'active' => false
]
],
'range' => []
]
],
1 => [
'code' => 'color',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => 'red',
'count' => 1,
'active' => true
],
1 => [
'label' => null,
'value' => 'white',
'count' => 1,
'active' => true
]
],
'range' => []
]
],
2 => [
'code' => 'size',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => 'xl',
'count' => 1,
'active' => true
],
1 => [
'label' => null,
'value' => 'xxl',
'count' => 0,
'active' => false
]
],
'range' => []
]
],
3 => [
'code' => 'price',
'label' => null,
'type' => 'range',
'items' => [
'list' => [],
'range' => [
0 => [
'label' => null,
'count' => 1,
'active' => true,
'fullRange' => [
'min' => 104.0,
'max' => 106.0
],
'activeRange' => [
'min' => 104.0,
'max' => 104.0
]
]
]
]
]
]
];
$this->assertEqualsCanonicalizing($expected, FormatData::formatDataWFacets($result));
}
public function testKeywordFilter()
{
$criteria = new Criteria();
$criteria->getSearch()->add(
new Search(
new Property('category_id'),
't-short',
),
);
$criteria->getFilters()->add(new FilterGroupCollection([
new Filter(
new Field('color'),
FilterOperator::EQ,
new FilterKeyword('white')
)
]));
$criteria->getFilters()->add(new FilterGroupCollection([
new Filter(
new Field('brand'),
FilterOperator::EQ,
new FilterKeyword('nike')
)
]));
$criteria->getFilters()->add(new FilterGroupCollection([
new Filter(
new Field('price'),
FilterOperator::GT,
new FilterNumber(100)
)
]));
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => [
'h2'
],
'facets' => [
0 => [
'code' => 'brand',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => 'nike',
'count' => 1,
'active' => true
],
1 => [
'label' => null,
'value' => 'rebook',
'count' => 1,
'active' => true
]
],
'range' => []
]
],
1 => [
'code' => 'color',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => 'red',
'count' => 1,
'active' => true
],
1 => [
'label' => null,
'value' => 'white',
'count' => 1,
'active' => true
]
],
'range' => []
]
],
2 => [
'code' => 'size',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => 'xl',
'count' => 0,
'active' => false
],
1 => [
'label' => null,
'value' => 'xxl',
'count' => 1,
'active' => true
]
],
'range' => []
]
],
3 => [
'code' => 'price',
'label' => null,
'type' => 'range',
'items' => [
'list' => [],
'range' => [
0 => [
'label' => null,
'count' => 1,
'active' => true,
'fullRange' => [
'min' => 104.0,
'max' => 106.0
],
'activeRange' => [
'min' => 105.0,
'max' => 105.0
]
]
]
]
]
]
];
$this->assertEqualsCanonicalizing($expected, FormatData::formatDataWFacets($result));
}
public function testKeywordFilterTwo()
{
$criteria = new Criteria();
$criteria->getSearch()->add(
new Search(
new Property('category_id'),
't-short',
),
);
$criteria->getFilters()->add(new FilterGroupCollection([
new Filter(
new Field('color'),
FilterOperator::EQ,
new FilterKeyword('white')
)
]));
$criteria->getFilters()->add(
(new FilterGroupCollection([
new Filter(
new Field('brand'),
FilterOperator::EQ,
new FilterKeyword('nike')
),
new Filter(
new Field('brand'),
FilterOperator::EQ,
new FilterKeyword('reebok')
)
]))
->setLogicOperator(LogicOperator::OR)
);
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => [
'h2'
],
'facets' => [
0 => [
'code' => 'brand',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => 'nike',
'count' => 1,
'active' => true
],
1 => [
'label' => null,
'value' => 'rebook',
'count' => 1,
'active' => true
]
],
'range' => []
]
],
1 => [
'code' => 'color',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => 'red',
'count' => 1,
'active' => true
],
1 => [
'label' => null,
'value' => 'white',
'count' => 1,
'active' => true
]
],
'range' => []
]
],
2 => [
'code' => 'size',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => 'xl',
'count' => 0,
'active' => false
],
1 => [
'label' => null,
'value' => 'xxl',
'count' => 1,
'active' => true
]
],
'range' => []
]
],
3 => [
'code' => 'price',
'label' => null,
'type' => 'range',
'items' => [
'list' => [],
'range' => [
0 => [
'label' => null,
'count' => 1,
'active' => true,
'fullRange' => [
'min' => 104.0,
'max' => 106.0
],
'activeRange' => [
'min' => 105.0,
'max' => 105.0
]
]
]
]
]
]
];
$this->assertEqualsCanonicalizing($expected, FormatData::formatDataWFacets($result));
}
}
\ No newline at end of file
<?php
namespace IQDEV\ElasticSearchTests\Filter;
use IQDEV\ElasticSearch\Criteria\Criteria;
use IQDEV\ElasticSearch\Criteria\Filter\Collection\FilterGroupCollection;
use IQDEV\ElasticSearch\Criteria\Filter\Field;
use IQDEV\ElasticSearch\Criteria\Filter\Filter;
use IQDEV\ElasticSearch\Criteria\Filter\FilterOperator;
use IQDEV\ElasticSearch\Criteria\Filter\Value\FilterKeyword;
use IQDEV\ElasticSearch\Criteria\Filter\Value\FilterNumber;
use IQDEV\ElasticSearch\Criteria\Query\SearchQuery;
use IQDEV\ElasticSearchTests\AbstractTestCase;
use IQDEV\ElasticSearchTests\Helpers\FormatData;
use IQDEV\ElasticSearchTests\Service\SearchClient;
class CommonRangeKeywordsTest extends AbstractTestCase
{
/**
* Поиск элементов по фильтру свойства и цене
*
* @return void
*/
public function testExistByFilterAndMinPrice(): void
{
$criteria = new Criteria();
$criteria->getFilters()->add(new FilterGroupCollection([
new Filter(
new Field('color'),
FilterOperator::EQ,
new FilterKeyword('red')
)
]));
$criteria->getFilters()->add(new FilterGroupCollection([
new Filter(
new Field('price'),
FilterOperator::GT,
new FilterNumber(102)
)
]));
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => [
'h1'
]
];
$this->assertEqualsCanonicalizing($expected, FormatData::formatData($result));
}
/**
* Поиск элементов по фильтру свойства и цене
*
* @return void
*/
public function testExistByFilterAndMaxPrice(): void
{
$criteria = new Criteria();
$criteria->getFilters()->add(new FilterGroupCollection([
new Filter(
new Field('color'),
FilterOperator::EQ,
new FilterKeyword('red')
)
]));
$criteria->getFilters()->add(new FilterGroupCollection([
new Filter(
new Field('price'),
FilterOperator::LT,
new FilterNumber(102)
)
]));
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => [
's2'
]
];
$this->assertEqualsCanonicalizing($expected, FormatData::formatData($result));
}
/**
* Поиск элементов по фильтру свойства и цене
*
* @return void
*/
public function testExistByFilterAndRangePrice(): void
{
$criteria = new Criteria();
$criteria->getFilters()->add(new FilterGroupCollection([
new Filter(
new Field('color'),
FilterOperator::EQ,
new FilterKeyword('red')
)
]));
$criteria->getFilters()->add(new FilterGroupCollection([
new Filter(
new Field('price'),
FilterOperator::GTE,
new FilterNumber(101)
),
new Filter(
new Field('price'),
FilterOperator::LTE,
new FilterNumber(104)
),
]));
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => [
'h1',
's2'
]
];
$this->assertEqualsCanonicalizing($expected, FormatData::formatData($result));
}
}
\ No newline at end of file
<?php
namespace IQDEV\ElasticSearchTests\Filter;
use Elastic\Elasticsearch\Client;
use IQDEV\ElasticSearch\Configuration;
use IQDEV\ElasticSearch\Converter\Result\EsResponseToResult;
use IQDEV\ElasticSearch\Indexer\IndexRunner;
use IQDEV\ElasticSearchTests\AbstractTestCase;
use IQDEV\ElasticSearchTests\Config\ChangingStateConfiguration;
use IQDEV\ElasticSearchTests\Factory\ClientFactory;
use IQDEV\ElasticSearchTests\Helpers\FormatData;
use IQDEV\ElasticSearchTests\Helpers\TestIndexProvider;
use Psr\Log\NullLogger;
class IndexesTest extends AbstractTestCase
{
private array $product = [
'id' => 'test',
'name' => 'Test товар',
'category' => 'indexes',
'properties' => [
'prop1' => 'value1',
'prop2' => 'value2',
'prop3' => 'value3',
]
];
private IndexRunner $indexRunner;
private Client $esClient;
private Configuration $configuration;
public function __construct(?string $name = null, array $data = [], $dataName = '')
{
parent::__construct($name, $data, $dataName);
$this->configuration = new ChangingStateConfiguration();
$this->esClient = ClientFactory::create();
$this->indexRunner = new IndexRunner(
$this->esClient,
$this->configuration,
new NullLogger()
);
}
public function testUpdate()
{
$indexProvider = new TestIndexProvider($this->configuration, [$this->product]);
$this->indexRunner->run($indexProvider);
$updateData = [
'id' => $this->product['id'],
'category' => $this->product['category'],
'type' => 'update',
'name' => 'Обновленный элемент'
];
$indexProvider = new TestIndexProvider($this->configuration, [$updateData]);
$this->indexRunner->run($indexProvider);
$response = $this->esClient->search([
'index' => $this->configuration->getIndexName(),
'body' => [
'query' => [
'match' => [
'_id' => $this->product['id']
],
]
]
]);
$esResponseToResult = new EsResponseToResult();
$result = $esResponseToResult->fromResponse($response, $this->configuration);
unset($updateData['type']);
$expected = [
'products' => [
array_merge($this->product, $updateData)
]
];
$this->assertEqualsCanonicalizing($expected, FormatData::formatDataProducts($result));
}
}
<?php
namespace IQDEV\ElasticSearchTests\Filter;
use IQDEV\ElasticSearch\Criteria\Criteria;
use IQDEV\ElasticSearch\Criteria\Filter\Collection\FilterGroupCollection;
use IQDEV\ElasticSearch\Criteria\Filter\Field;
use IQDEV\ElasticSearch\Criteria\Filter\Filter;
use IQDEV\ElasticSearch\Criteria\Filter\FilterOperator;
use IQDEV\ElasticSearch\Criteria\Filter\Value\FilterKeyword;
use IQDEV\ElasticSearch\Criteria\Query\SearchQuery;
use IQDEV\ElasticSearch\Criteria\Search\Search;
use IQDEV\ElasticSearch\Document\Property\Property;
use IQDEV\ElasticSearchTests\AbstractTestCase;
use IQDEV\ElasticSearchTests\Helpers\FormatData;
use IQDEV\ElasticSearchTests\Service\SearchClient;
class KeywordsTest extends AbstractTestCase
{
/**
* Поиск элементов по пустому фильтру свойства
*
* @return void
*/
public function testExistByEmptyFilter(): void
{
$criteria = new Criteria();
$criteria->getFilters()->add(new FilterGroupCollection([
new Filter(
new Field('color'),
FilterOperator::EQ,
new FilterKeyword('')
)
]));
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => []
];
$this->assertEquals($expected, FormatData::formatData($result));
}
/**
* Поиск элементов по фильтру свойства
*
* @return void
*/
public function testExistByFilter(): void
{
$criteria = new Criteria();
$criteria->getFilters()->add(new FilterGroupCollection([
new Filter(
new Field('color'),
FilterOperator::EQ,
new FilterKeyword('red')
)
]));
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => [
's2',
'h1'
]
];
$this->assertEqualsCanonicalizing($expected, FormatData::formatData($result));
}
/**
* Поиск элементов по фильтру свойства и категории
*
* @return void
*/
public function testExistByFilterAndCategory(): void
{
$criteria = new Criteria();
$criteria->getSearch()->add(
new Search(
new Property('category_id'),
'shoes',
),
);
$criteria->getFilters()->add(new FilterGroupCollection([
new Filter(
new Field('color'),
FilterOperator::EQ,
new FilterKeyword('red')
)
]));
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => [
's2',
]
];
$this->assertEquals($expected, FormatData::formatData($result));
}
/**
* Поиск элементов по нескольким свойствам
*
* @return void
*/
public function testExistByMultipleFilter(): void
{
$criteria = new Criteria();
$criteria->getFilters()->add(new FilterGroupCollection([
new Filter(
new Field('color'),
FilterOperator::EQ,
new FilterKeyword('red')
),
new Filter(
new Field('size'),
FilterOperator::EQ,
new FilterKeyword('xxl')
)
]));
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => []
];
$this->assertEquals($expected, FormatData::formatData($result));
}
/**
* Поиск элементов по нескольким свойствам
*
* @return void
*/
public function testExistByMultipleFilter2(): void
{
$criteria = new Criteria();
$criteria->getFilters()->add(new FilterGroupCollection([
new Filter(
new Field('color'),
FilterOperator::EQ,
new FilterKeyword('red')
),
new Filter(
new Field('size'),
FilterOperator::EQ,
new FilterKeyword('xl')
)
]));
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => [
'h1'
]
];
$this->assertEquals($expected, FormatData::formatData($result));
}
/**
* Поиск элементов по нескольким свойствам и категории
*
* @return void
*/
public function testExistByMultipleFilterAndCategory(): void
{
$criteria = new Criteria();
$criteria->getSearch()->add(
new Search(
new Property('category_id'),
'prices',
),
);
$criteria->getFilters()->add(new FilterGroupCollection([
new Filter(
new Field('color'),
FilterOperator::EQ,
new FilterKeyword('red')
),
new Filter(
new Field('size'),
FilterOperator::EQ,
new FilterKeyword('xl')
)
]));
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => []
];
$this->assertEquals($expected, FormatData::formatData($result));
}
}
\ No newline at end of file
<?php
namespace IQDEV\ElasticSearchTests\Filter;
use IQDEV\ElasticSearch\Criteria\Criteria;
use IQDEV\ElasticSearch\Criteria\Filter\Collection\FilterGroupCollection;
use IQDEV\ElasticSearch\Criteria\Filter\Field;
use IQDEV\ElasticSearch\Criteria\Filter\Filter;
use IQDEV\ElasticSearch\Criteria\Filter\FilterOperator;
use IQDEV\ElasticSearch\Criteria\Filter\FilterType;
use IQDEV\ElasticSearch\Criteria\Filter\LogicOperator;
use IQDEV\ElasticSearch\Criteria\Filter\Value\FilterKeyword;
use IQDEV\ElasticSearch\Criteria\Filter\Value\FilterNumber;
use IQDEV\ElasticSearch\Criteria\Query\SearchQuery;
use IQDEV\ElasticSearchTests\AbstractTestCase;
use IQDEV\ElasticSearchTests\Helpers\FormatData;
use IQDEV\ElasticSearchTests\Service\SearchClient;
class QueryAndPostFilterTest extends AbstractTestCase
{
/**
* query по не сущ бренду
*/
public function testQueryNonExistentBrand()
{
$criteria = new Criteria();
$filterCollectionBrand = new FilterGroupCollection([
new Filter(
new Field('brand'),
FilterOperator::EQ,
new FilterKeyword('not')
)
]);
$filterCollectionBrand->setFilterType(FilterType::QUERY);
$criteria->getFilters()->add($filterCollectionBrand);
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => [],
'facets' => []
];
$this->assertEqualsCanonicalizing($expected, FormatData::formatDataWFacets($result));
}
/**
* query по сущ бренду
* @return void
*/
public function testQueryExistingBrand()
{
$criteria = new Criteria();
$filterCollectionBrand = new FilterGroupCollection([
new Filter(
new Field('brand'),
FilterOperator::EQ,
new FilterKeyword('adidas')
)
]);
$filterCollectionBrand->setFilterType(FilterType::QUERY);
$criteria->getFilters()->add($filterCollectionBrand);
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => [
's1',
's2',
],
'facets' => [
0 => [
'code' => 'brand',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => 'adidas',
'count' => 2,
'active' => true,
]
],
'range' => [],
]
],
1 => [
'code' => 'color',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => 'green',
'count' => 1,
'active' => true,
],
1 => [
'label' => null,
'value' => 'red',
'count' => 1,
'active' => true,
]
],
'range' => [],
]
],
2 => [
'code' => 'size',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => '46',
'count' => 1,
'active' => true,
],
1 => [
'label' => null,
'value' => '47',
'count' => 1,
'active' => true,
]
],
'range' => [],
]
],
3 => [
'code' => 'price',
'label' => null,
'type' => 'range',
'items' => [
'list' => [],
'range' => [
0 => [
'label' => null,
'count' => 2,
'active' => true,
'fullRange' => [
'min' => 100.0,
'max' => 101.0,
],
'activeRange' => [
'min' => 100.0,
'max' => 101.0,
]
]
]
]
]
],
];
$this->assertEqualsCanonicalizing($expected, FormatData::formatDataWFacets($result));
}
/**
* query по сущ бренду и post_filter по бренду
* @return void
*/
public function testQueryExistingBrandAndPostFilterExistingBrand()
{
$criteria = new Criteria();
$filterCollectionBrand = new FilterGroupCollection([
new Filter(
new Field('brand'),
FilterOperator::EQ,
new FilterKeyword('adidas')
),
new Filter(
new Field('brand'),
FilterOperator::EQ,
new FilterKeyword('nike')
),
]);
$filterCollectionBrand
->setLogicOperator(LogicOperator::OR)
->setFilterType(FilterType::QUERY);
$criteria->getFilters()->add($filterCollectionBrand);
$filterCollectionBrand = new FilterGroupCollection([
new Filter(
new Field('brand'),
FilterOperator::EQ,
new FilterKeyword('nike')
),
]);
$criteria->getFilters()->add($filterCollectionBrand);
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => [
's4',
'h1',
'h2',
],
'facets' => [
0 => [
'code' => 'brand',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => 'adidas',
'count' => 2,
'active' => true,
],
1 => [
'label' => null,
'value' => 'nike',
'count' => 3,
'active' => true,
]
],
'range' => [],
]
],
1 => [
'code' => 'color',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => 'green',
'count' => 1,
'active' => true,
],
1 => [
'label' => null,
'value' => 'red',
'count' => 1,
'active' => true,
],
2 => [
'label' => null,
'value' => 'white',
'count' => 1,
'active' => true,
]
],
'range' => [],
]
],
2 => [
'code' => 'size',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => '43',
'count' => 1,
'active' => true,
],
1 => [
'label' => null,
'value' => '46',
'count' => 0,
'active' => false,
],
2 => [
'label' => null,
'value' => '47',
'count' => 0,
'active' => false,
],
3 => [
'label' => null,
'value' => 'xl',
'count' => 1,
'active' => true,
],
4 => [
'label' => null,
'value' => 'xxl',
'count' => 1,
'active' => true,
]
],
'range' => [],
],
],
3 => [
'code' => 'price',
'label' => null,
'type' => 'range',
'items' => [
'list' => [],
'range' => [
0 => [
'label' => null,
'count' => 3,
'active' => true,
'fullRange' => [
'min' => 100.0,
'max' => 105.0,
],
'activeRange' => [
'min' => 103.0,
'max' => 105.0,
]
]
]
]
]
]
];
$this->assertEqualsCanonicalizing($expected, FormatData::formatDataWFacets($result));
}
/**
* query по сущ бренду и post_filter по цвету
* @return void
*/
public function testQueryExistingBrandAndPostFilterExistingColor()
{
$criteria = new Criteria();
$filterCollectionBrand = new FilterGroupCollection([
new Filter(
new Field('brand'),
FilterOperator::EQ,
new FilterKeyword('nike')
),
]);
$filterCollectionBrand
->setLogicOperator(LogicOperator::OR)
->setFilterType(FilterType::QUERY);
$criteria->getFilters()->add($filterCollectionBrand);
$filterCollectionColor = new FilterGroupCollection([
new Filter(
new Field('color'),
FilterOperator::EQ,
new FilterKeyword('white')
),
]);
$criteria->getFilters()->add($filterCollectionColor);
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => [
'h2',
],
'facets' => [
0 => [
'code' => 'brand',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => 'nike',
'count' => 1,
'active' => true,
]
],
'range' => [],
]
],
1 => [
'code' => 'color',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => 'green',
'count' => 1,
'active' => true,
],
1 => [
'label' => null,
'value' => 'red',
'count' => 1,
'active' => true,
],
2 => [
'label' => null,
'value' => 'white',
'count' => 1,
'active' => true,
]
],
'range' => [],
]
],
2 => [
'code' => 'size',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => '43',
'count' => 0,
'active' => false,
],
1 => [
'label' => null,
'value' => 'xl',
'count' => 0,
'active' => false,
],
2 => [
'label' => null,
'value' => 'xxl',
'count' => 1,
'active' => true,
]
],
'range' => [],
]
],
3 => [
'code' => 'price',
'label' => null,
'type' => 'range',
'items' => [
'list' => [],
'range' => [
0 => [
'label' => null,
'count' => 1,
'active' => true,
'fullRange' => [
'min' => 103.0,
'max' => 105.0,
],
'activeRange' => [
'min' => 105.0,
'max' => 105.0,
]
]
]
]
]
]
];
$this->assertEqualsCanonicalizing($expected, FormatData::formatDataWFacets($result));
}
/**
* query по сущ бренду и цвету и post_filter по бренду
* @return void
*/
public function testQueryExistingBrandAndColorAndPostFilterExistingColor()
{
$criteria = new Criteria();
$filterCollectionBrand = new FilterGroupCollection([
new Filter(
new Field('brand'),
FilterOperator::EQ,
new FilterKeyword('nike')
),
new Filter(
new Field('brand'),
FilterOperator::EQ,
new FilterKeyword('rebook')
),
]);
$filterCollectionBrand
->setLogicOperator(LogicOperator::OR)
->setFilterType(FilterType::QUERY);
$criteria->getFilters()->add($filterCollectionBrand);
$filterCollectionColor = new FilterGroupCollection([
new Filter(
new Field('color'),
FilterOperator::EQ,
new FilterKeyword('white')
),
]);
$filterCollectionColor->setFilterType(FilterType::QUERY);
$criteria->getFilters()->add($filterCollectionColor);
$filterCollectionBrand = new FilterGroupCollection([
new Filter(
new Field('brand'),
FilterOperator::EQ,
new FilterKeyword('nike')
),
]);
$criteria->getFilters()->add($filterCollectionBrand);
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => [
'h2',
],
'facets' => [
0 => [
'code' => 'brand',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => 'nike',
'count' => 1,
'active' => true,
],
1 => [
'label' => null,
'value' => 'rebook',
'count' => 2,
'active' => true,
]
],
'range' => []
]
],
1 => [
'code' => 'color',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => 'white',
'count' => 1,
'active' => true,
]
],
'range' => []
]
],
2 => [
'code' => 'size',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => 'xl',
'count' => 0,
'active' => false,
],
1 => [
'label' => null,
'value' => 'xxl',
'count' => 1,
'active' => true,
]
],
'range' => []
]
],
3 => [
'code' => 'price',
'label' => null,
'type' => 'range',
'items' => [
'list' => [],
'range' => [
0 => [
'label' => null,
'count' => 1,
'active' => true,
'fullRange' => [
'min' => 105.0,
'max' => 107.0,
],
'activeRange' => [
'min' => 105.0,
'max' => 105.0,
]
]
]
]
]
]
];
$this->assertEqualsCanonicalizing($expected, FormatData::formatDataWFacets($result));
}
/**
* query по сущ бренду и post_filter по бренду и цвету
* @return void
*/
public function testQueryExistingBrandAndPostFilterExistingBrandAndColor()
{
$criteria = new Criteria();
$filterCollectionBrand = new FilterGroupCollection([
new Filter(
new Field('brand'),
FilterOperator::EQ,
new FilterKeyword('nike')
),
new Filter(
new Field('brand'),
FilterOperator::EQ,
new FilterKeyword('rebook')
),
]);
$filterCollectionBrand
->setLogicOperator(LogicOperator::OR)
->setFilterType(FilterType::QUERY);
$criteria->getFilters()->add($filterCollectionBrand);
$filterCollectionBrand = new FilterGroupCollection([
new Filter(
new Field('brand'),
FilterOperator::EQ,
new FilterKeyword('nike')
),
]);
$criteria->getFilters()->add($filterCollectionBrand);
$filterCollectionColor = new FilterGroupCollection([
new Filter(
new Field('color'),
FilterOperator::EQ,
new FilterKeyword('red')
),
]);
$criteria->getFilters()->add($filterCollectionColor);
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => [
'h1',
],
'facets' => [
0 => [
'code' => 'brand',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => 'nike',
'count' => 1,
'active' => true,
],
1 => [
'label' => null,
'value' => 'rebook',
'count' => 0,
'active' => false,
]
],
'range' => []
]
],
1 => [
'code' => 'color',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => 'blue',
'count' => 0,
'active' => false,
],
1 => [
'label' => null,
'value' => 'green',
'count' => 1,
'active' => true,
],
2 => [
'label' => null,
'value' => 'red',
'count' => 1,
'active' => true,
],
3 => [
'label' => null,
'value' => 'white',
'count' => 1,
'active' => true,
]
],
'range' => []
]
],
2 => [
'code' => 'size',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => '43',
'count' => 0,
'active' => false,
],
1 => [
'label' => null,
'value' => '47',
'count' => 0,
'active' => false,
],
2 => [
'label' => null,
'value' => 'xl',
'count' => 1,
'active' => true,
],
3 => [
'label' => null,
'value' => 'xxl',
'count' => 0,
'active' => false,
]
],
'range' => []
]
],
3 => [
'code' => 'price',
'label' => null,
'type' => 'range',
'items' => [
'list' => [],
'range' => [
0 => [
'label' => null,
'count' => 1,
'active' => true,
'fullRange' => [
'min' => 102.0,
'max' => 107.0,
],
'activeRange' => [
'min' => 104.0,
'max' => 104.0,
]
]
]
]
]
]
];
$this->assertEqualsCanonicalizing($expected, FormatData::formatDataWFacets($result));
}
/**
* query по не сущ цене
* @return void
*/
public function testQueryNonExistentPrice()
{
$criteria = new Criteria();
$filterCollectionPrice = new FilterGroupCollection([
new Filter(
new Field('price'),
FilterOperator::GTE,
new FilterNumber(108)
)
]);
$filterCollectionPrice->setFilterType(FilterType::QUERY);
$criteria->getFilters()->add($filterCollectionPrice);
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => [],
'facets' => [],
];
$this->assertEqualsCanonicalizing($expected, FormatData::formatDataWFacets($result));
}
/**
* query по сущ цене
* @return void
*/
public function testQueryExistingPrice()
{
$criteria = new Criteria();
$filterCollectionPrice = new FilterGroupCollection([
new Filter(
new Field('price'),
FilterOperator::GTE,
new FilterNumber(105)
)
]);
$filterCollectionPrice->setFilterType(FilterType::QUERY);
$criteria->getFilters()->add($filterCollectionPrice);
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => [
'h2',
'h3',
'p1',
],
'facets' => [
0 => [
'code' => 'brand',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => 'nike',
'count' => 1,
'active' => true,
],
1 => [
'label' => null,
'value' => 'rebook',
'count' => 2,
'active' => true,
]
],
'range' => [],
]
],
1 => [
'code' => 'color',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => 'white',
'count' => 3,
'active' => true,
]
],
'range' => []
]
],
2 => [
'code' => 'size',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => 'xl',
'count' => 2,
'active' => true,
],
1 => [
'label' => null,
'value' => 'xxl',
'count' => 1,
'active' => true,
]
],
'range' => []
]
],
3 => [
'code' => 'price',
'label' => null,
'type' => 'range',
'items' => [
'list' => [],
'range' => [
0 => [
'label' => null,
'count' => 3,
'active' => true,
'fullRange' => [
'min' => 105.0,
'max' => 107.0,
],
'activeRange' => [
'min' => 105.0,
'max' => 107.0,
]
]
]
]
]
]
];
$this->assertEqualsCanonicalizing($expected, FormatData::formatDataWFacets($result));
}
/**
* query по сущ цене и бренду
* @return void
*/
public function testQueryExistingPriceAndBrand()
{
$criteria = new Criteria();
$filterCollection = new FilterGroupCollection([
new Filter(
new Field('price'),
FilterOperator::GTE,
new FilterNumber(104)
),
new Filter(
new Field('brand'),
FilterOperator::EQ,
new FilterKeyword('nike')
),
]);
$filterCollection->setFilterType(FilterType::QUERY);
$criteria->getFilters()->add($filterCollection);
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => [
'h1',
'h2',
],
'facets' => [
0 => [
'code' => 'brand',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => 'nike',
'count' => 2,
'active' => true,
]
],
'range' => []
]
],
1 => [
'code' => 'color',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => 'red',
'count' => 1,
'active' => true,
],
1 => [
'label' => null,
'value' => 'white',
'count' => 1,
'active' => true,
]
],
'range' => []
]
],
2 => [
'code' => 'size',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => 'xl',
'count' => 1,
'active' => true,
],
1 => [
'label' => null,
'value' => 'xxl',
'count' => 1,
'active' => true,
]
],
'range' => []
]
],
3 => [
'code' => 'price',
'label' => null,
'type' => 'range',
'items' => [
'list' => [],
'range' => [
0 => [
'label' => null,
'count' => 2,
'active' => true,
'fullRange' => [
'min' => 104.0,
'max' => 105.0,
],
'activeRange' => [
'min' => 104.0,
'max' => 105.0,
]
]
]
]
]
]
];
$this->assertEqualsCanonicalizing($expected, FormatData::formatDataWFacets($result));
}
/**
* query по сущ цене и бренду и post_filter по цвету
* @return void
*/
public function testQueryExistingPriceAndBrandAndPostFilterColor()
{
$criteria = new Criteria();
$filterCollection = new FilterGroupCollection([
new Filter(
new Field('price'),
FilterOperator::GTE,
new FilterNumber(104)
),
new Filter(
new Field('brand'),
FilterOperator::EQ,
new FilterKeyword('nike')
),
]);
$filterCollection->setFilterType(FilterType::QUERY);
$criteria->getFilters()->add($filterCollection);
$filterCollectionColor = new FilterGroupCollection([
new Filter(
new Field('color'),
FilterOperator::EQ,
new FilterKeyword('red')
),
]);
$criteria->getFilters()->add($filterCollectionColor);
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => [
'h1',
],
'facets' => [
0 => [
'code' => 'brand',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => 'nike',
'count' => 1,
'active' => true,
]
],
'range' => []
]
],
1 => [
'code' => 'color',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => 'red',
'count' => 1,
'active' => true,
],
1 => [
'label' => null,
'value' => 'white',
'count' => 1,
'active' => true,
]
],
'range' => []
]
],
2 => [
'code' => 'size',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => 'xl',
'count' => 1,
'active' => true,
],
1 => [
'label' => null,
'value' => 'xxl',
'count' => 0,
'active' => false,
]
],
'range' => []
]
],
3 => [
'code' => 'price',
'label' => null,
'type' => 'range',
'items' => [
'list' => [],
'range' => [
0 => [
'label' => null,
'count' => 1,
'active' => true,
'fullRange' => [
'min' => 104.0,
'max' => 105.0,
],
'activeRange' => [
'min' => 104.0,
'max' => 104.0,
]
]
]
]
]
]
];
$this->assertEqualsCanonicalizing($expected, FormatData::formatDataWFacets($result));
}
/**
* query по сущ цене и бренду и post_filter по цвету и бренду
* @return void
*/
public function testQueryExistingPriceAndBrandAndPostFilterColorAndBrand()
{
$criteria = new Criteria();
$filterCollectionPrice = new FilterGroupCollection([
new Filter(
new Field('price'),
FilterOperator::LTE,
new FilterNumber(104)
),
]);
$filterCollectionPrice->setFilterType(FilterType::QUERY);
$criteria->getFilters()->add($filterCollectionPrice);
$filterCollectionBrand = new FilterGroupCollection([
new Filter(
new Field('brand'),
FilterOperator::EQ,
new FilterKeyword('nike')
),
new Filter(
new Field('brand'),
FilterOperator::EQ,
new FilterKeyword('adidas')
),
]);
$filterCollectionBrand
->setLogicOperator(LogicOperator::OR)
->setFilterType(FilterType::QUERY);
$criteria->getFilters()->add($filterCollectionBrand);
$filterCollectionColor = new FilterGroupCollection([
new Filter(
new Field('color'),
FilterOperator::EQ,
new FilterKeyword('green')
),
]);
$criteria->getFilters()->add($filterCollectionColor);
$filterCollectionBrand = new FilterGroupCollection([
new Filter(
new Field('brand'),
FilterOperator::EQ,
new FilterKeyword('nike')
),
]);
$criteria->getFilters()->add($filterCollectionBrand);
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => [
's4',
],
'facets' => [
0 => [
'code' => 'brand',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => 'adidas',
'count' => 1,
'active' => true,
],
1 => [
'label' => null,
'value' => 'nike',
'count' => 1,
'active' => true,
]
],
'range' => []
]
],
1 => [
'code' => 'color',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => 'green',
'count' => 1,
'active' => true,
],
1 => [
'label' => null,
'value' => 'red',
'count' => 1,
'active' => true,
]
],
'range' => []
]
],
2 => [
'code' => 'size',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => '43',
'count' => 1,
'active' => true,
],
1 => [
'label' => null,
'value' => '46',
'count' => 0,
'active' => false,
],
2 => [
'label' => null,
'value' => '47',
'count' => 0,
'active' => false,
],
3 => [
'label' => null,
'value' => 'xl',
'count' => 0,
'active' => false,
]
],
'range' => []
]
],
3 => [
'code' => 'price',
'label' => null,
'type' => 'range',
'items' => [
'list' => [],
'range' => [
0 => [
'label' => null,
'count' => 1,
'active' => true,
'fullRange' => [
'min' => 100.0,
'max' => 104.0,
],
'activeRange' => [
'min' => 103.0,
'max' => 103.0,
]
]
]
]
]
]
];
$this->assertEqualsCanonicalizing($expected, FormatData::formatDataWFacets($result));
}
/**
* query по сущ цене и бренду и post_filter по цене
* @return void
*/
public function testQueryExistingPriceAndBrandAndPostFilterPrice()
{
$criteria = new Criteria();
$filterCollectionPrice = new FilterGroupCollection([
new Filter(
new Field('price'),
FilterOperator::LTE,
new FilterNumber(104)
),
]);
$filterCollectionPrice->setFilterType(FilterType::QUERY);
$criteria->getFilters()->add($filterCollectionPrice);
$filterCollectionBrand = new FilterGroupCollection([
new Filter(
new Field('brand'),
FilterOperator::EQ,
new FilterKeyword('nike')
),
new Filter(
new Field('brand'),
FilterOperator::EQ,
new FilterKeyword('adidas')
),
]);
$filterCollectionBrand
->setLogicOperator(LogicOperator::OR)
->setFilterType(FilterType::QUERY);
$criteria->getFilters()->add($filterCollectionBrand);
$filterCollectionPrice = new FilterGroupCollection([
new Filter(
new Field('price'),
FilterOperator::GTE,
new FilterNumber(102)
),
]);
$criteria->getFilters()->add($filterCollectionPrice);
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => [
's4',
'h1',
],
'facets' => [
0 => [
'code' => 'brand',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => 'adidas',
'count' => 0,
'active' => false,
],
1 => [
'label' => null,
'value' => 'nike',
'count' => 2,
'active' => true,
]
],
'range' => []
]
],
1 => [
'code' => 'color',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => 'green',
'count' => 1,
'active' => true,
],
1 => [
'label' => null,
'value' => 'red',
'count' => 1,
'active' => true,
]
],
'range' => []
]
],
2 => [
'code' => 'size',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => '43',
'count' => 1,
'active' => true,
],
1 => [
'label' => null,
'value' => '46',
'count' => 0,
'active' => false,
],
2 => [
'label' => null,
'value' => '47',
'count' => 0,
'active' => false,
],
3 => [
'label' => null,
'value' => 'xl',
'count' => 1,
'active' => true,
]
],
'range' => [],
]
],
3 => [
'code' => 'price',
'label' => null,
'type' => 'range',
'items' => [
'list' => [],
'range' => [
0 => [
'label' => null,
'count' => 2,
'active' => true,
'fullRange' => [
'min' => 100.0,
'max' => 104.0,
],
'activeRange' => [
'min' => 103.0,
'max' => 104.0,
]
]
]
]
]
]
];
$this->assertEqualsCanonicalizing($expected, FormatData::formatDataWFacets($result));
}
/**
* query по сущ цене и бренду и post_filter по цвету и цене
* @return void
*/
public function testQueryExistingPriceAndBrandAndPostFilterPriceAndColor()
{
$criteria = new Criteria();
$filterCollectionPrice = new FilterGroupCollection([
new Filter(
new Field('price'),
FilterOperator::LTE,
new FilterNumber(104)
),
]);
$filterCollectionPrice->setFilterType(FilterType::QUERY);
$criteria->getFilters()->add($filterCollectionPrice);
$filterCollectionBrand = new FilterGroupCollection([
new Filter(
new Field('brand'),
FilterOperator::EQ,
new FilterKeyword('nike')
),
new Filter(
new Field('brand'),
FilterOperator::EQ,
new FilterKeyword('adidas')
),
]);
$filterCollectionBrand
->setLogicOperator(LogicOperator::OR)
->setFilterType(FilterType::QUERY);
$criteria->getFilters()->add($filterCollectionBrand);
$filterCollectionPrice = new FilterGroupCollection([
new Filter(
new Field('price'),
FilterOperator::GTE,
new FilterNumber(101)
),
]);
$criteria->getFilters()->add($filterCollectionPrice);
$filterCollectionColor = new FilterGroupCollection([
new Filter(
new Field('color'),
FilterOperator::EQ,
new FilterKeyword('green')
),
]);
$criteria->getFilters()->add($filterCollectionColor);
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => [
's4',
],
'facets' => [
0 => [
'code' => 'brand',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => 'adidas',
'count' => 0,
'active' => false,
],
1 => [
'label' => null,
'value' => 'nike',
'count' => 1,
'active' => true,
]
],
'range' => []
]
],
1 => [
'code' => 'color',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => 'green',
'count' => 1,
'active' => true,
],
1 => [
'label' => null,
'value' => 'red',
'count' => 2,
'active' => true,
]
],
'range' => []
]
],
2 => [
'code' => 'size',
'label' => null,
'type' => 'list',
'items' => [
'list' => [
0 => [
'label' => null,
'value' => '43',
'count' => 1,
'active' => true,
],
1 => [
'label' => null,
'value' => '46',
'count' => 0,
'active' => false,
],
2 => [
'label' => null,
'value' => '47',
'count' => 0,
'active' => false,
],
3 => [
'label' => null,
'value' => 'xl',
'count' => 0,
'active' => false,
]
],
'range' => []
]
],
3 => [
'code' => 'price',
'label' => null,
'type' => 'range',
'items' => [
'list' => [],
'range' => [
0 => [
'label' => null,
'count' => 1,
'active' => true,
'fullRange' => [
'min' => 100.0,
'max' => 104.0,
],
'activeRange' => [
'min' => 103.0,
'max' => 103.0,
],
]
]
]
]
]
];
$this->assertEqualsCanonicalizing($expected, FormatData::formatDataWFacets($result));
}
}
<?php
namespace IQDEV\ElasticSearchTests\Filter;
use IQDEV\ElasticSearch\Config\BaseConfiguration;
use IQDEV\ElasticSearch\Converter\Request\CriteriaToRequest;
use IQDEV\ElasticSearch\Criteria\Criteria;
use IQDEV\ElasticSearch\Criteria\Filter\Collection\FilterGroupCollection;
use IQDEV\ElasticSearch\Criteria\Filter\Field;
use IQDEV\ElasticSearch\Criteria\Filter\Filter;
use IQDEV\ElasticSearch\Criteria\Filter\FilterOperator;
use IQDEV\ElasticSearch\Criteria\Filter\FilterType;
use IQDEV\ElasticSearch\Criteria\Filter\Value\FilterKeyword;
use IQDEV\ElasticSearch\Criteria\Filter\Value\FilterNumber;
use IQDEV\ElasticSearch\Criteria\Query\SearchQuery;
use IQDEV\ElasticSearch\Criteria\Search\Search;
use IQDEV\ElasticSearch\Document\Property\Property;
use IQDEV\ElasticSearchTests\AbstractTestCase;
use IQDEV\ElasticSearchTests\Helpers\FormatData;
use IQDEV\ElasticSearchTests\Service\SearchClient;
/**
* Тестирование агрегирующих функций
*/
class QueryTest extends AbstractTestCase
{
public function testFilterChangeFromPostToQuery()
{
$search = [
'category' => [
'key' => 'category_id',
'value' => 'shoes',
],
];
$filter = [
'brand' => [
'key' => 'brand',
'value' => 'nike',
],
'price' => [
'key' => 'price',
'max' => 100.0,
'min' => 10.0,
]
];
$criteria = new Criteria();
$criteria->getSearch()->add(
new Search(
new Property($search['category']['key']),
$search['category']['value'],
),
);
$filterCollectionCategory = new FilterGroupCollection();
$filterCollectionCategory->setFilterType(FilterType::QUERY);
$criteria->getFilters()->add($filterCollectionCategory);
$filterCollectionBrand = new FilterGroupCollection([
new Filter(
new Field($filter['brand']['key']),
FilterOperator::EQ,
new FilterKeyword($filter['brand']['value'])
)
]);
$filterCollectionPrice = new FilterGroupCollection([
new Filter(
new Field($filter['price']['key']),
FilterOperator::LT,
new FilterNumber($filter['price']['min'])
),
new Filter(
new Field($filter['price']['key']),
FilterOperator::GT,
new FilterNumber($filter['price']['max'])
),
]);
// Формирование фильтра для post
$criteriaPost = clone $criteria;
$criteriaPost->getFilters()->add(clone $filterCollectionPrice);
$criteriaPost->getFilters()->add(clone $filterCollectionBrand);
// Формирование фильтра для query
$criteriaQuery = clone $criteria;
$filterTypeQuery = FilterType::QUERY;
$filterCollectionPrice->setFilterType($filterTypeQuery);
$filterCollectionBrand->setFilterType($filterTypeQuery);
$criteriaQuery->getFilters()->add(clone $filterCollectionPrice);
$criteriaQuery->getFilters()->add(clone $filterCollectionBrand);
// Получение классов с данными для запроса в es
$criteriaToRequest = new CriteriaToRequest(new BaseConfiguration());
$requestPost = $criteriaToRequest->fromCriteria($criteriaPost);
$requestQuery = $criteriaToRequest->fromCriteria($criteriaQuery);
$expectedFilter = [
[
"nested" => [
"path" => "search_data",
"query" => [
"bool" => [
"filter" => [
[
"nested" => [
"path" => "search_data.number_facet",
"query" => [
"bool" => [
"filter" => [
[
"term" => [
"search_data.number_facet.facet_code" => $filter['price']['key']
]
],
[
"range" => [
"search_data.number_facet.facet_value" => [
"lt" => $filter['price']['min'],
"gt" => $filter['price']['max'],
]
]
]
]
]
]
]
]
]
]
]
]
],
[
"nested" => [
"path" => "search_data",
"query" => [
"bool" => [
"filter" => [
[
"nested" => [
"path" => "search_data.keyword_facet",
"query" => [
"bool" => [
"filter" => [
[
"term" => [
"search_data.keyword_facet.facet_code" => $filter['brand']['key']
]
],
[
"term" => [
"search_data.keyword_facet.facet_value" => $filter['brand']['value']
]
]
]
]
]
]
]
]
]
]
]
],
];
$expected = [
"query" => [
"bool" => [
"must" => [
[
"term" => [
"category_id" => $search['category']['value']
]
],
]
]
],
];
$this->assertArray(
array_merge($expected, [
"query" => [
"bool" => [
"filter" => $expectedFilter,
]
]
]),
$requestQuery->es(),
'query response'
);
$this->assertArray(
array_merge($expected, [
"post_filter" => [
"bool" => [
"filter" => $expectedFilter,
]
]
]),
$requestPost->es(),
'post response'
);
}
public function testAddingASingleKeyFilterToPostAndQuery()
{
$filter = [
'price' => [
'key' => 'price',
'max' => 100.0,
'min' => 10.0,
'lower' => 0.0,
]
];
$criteria = new Criteria();
$filterCollectionPrice = new FilterGroupCollection([
new Filter(
new Field($filter['price']['key']),
FilterOperator::LT,
new FilterNumber($filter['price']['min'])
),
new Filter(
new Field($filter['price']['key']),
FilterOperator::GT,
new FilterNumber($filter['price']['max'])
),
]);
$criteria->getFilters()->add($filterCollectionPrice);
$filterCollectionQueryPrice = new FilterGroupCollection([
new Filter(
new Field($filter['price']['key']),
FilterOperator::LT,
new FilterNumber($filter['price']['lower'])
),
]);
$filterCollectionQueryPrice->setFilterType(FilterType::QUERY);
$criteria->getFilters()->add($filterCollectionQueryPrice);
$criteriaToRequest = new CriteriaToRequest(new BaseConfiguration());
$request = $criteriaToRequest->fromCriteria($criteria);
$expected = [
"post_filter" => [
"bool" => [
"filter" => [
0 => [
"nested" => [
"path" => "search_data",
"query" => [
"bool" => [
"filter" => [
0 => [
"nested" => [
"path" => "search_data.number_facet",
"query" => [
"bool" => [
"filter" => [
[
"term" => [
"search_data.number_facet.facet_code" => "price"
]
],
[
"range" => [
"search_data.number_facet.facet_value" => [
"lt" => $filter['price']['min'],
"gt" => $filter['price']['max'],
]
]
]
]
]
]
]
]
]
]
]
]
]
]
]
],
"query" => [
"bool" => [
"filter" => [
0 => [
"nested" => [
"path" => "search_data",
"query" => [
"bool" => [
"filter" => [
0 => [
"nested" => [
"path" => "search_data.number_facet",
"query" => [
"bool" => [
"filter" => [
0 => [
"term" => [
"search_data.number_facet.facet_code" => "price"
]
],
1 => [
"range" => [
"search_data.number_facet.facet_value" => [
"lt" => $filter['price']['lower']
]
]
]
]
]
]
]
]
]
]
]
]
]
]
]
]
];
$this->assertArray($expected, $request->es());
}
public function testGlobalFilterPrice()
{
$filter = [
'price' => [
'key' => 'price',
'min' => 105,
'lower' => 103,
]
];
$criteria = new Criteria();
$filterCollectionPrice = new FilterGroupCollection([
new Filter(
new Field($filter['price']['key']),
FilterOperator::GTE,
new FilterNumber($filter['price']['min'])
)
]);
$criteria->getFilters()->add($filterCollectionPrice);
$filterCollectionQueryPrice = new FilterGroupCollection([
new Filter(
new Field($filter['price']['key']),
FilterOperator::GTE,
new FilterNumber($filter['price']['lower'])
),
]);
$filterCollectionQueryPrice->setFilterType(FilterType::QUERY);
$criteria->getFilters()->add($filterCollectionQueryPrice);
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => [
'h2',
'h3',
'p1',
],
"facets" => [
0 => [
"code" => "brand",
"label" => null,
"type" => "list",
"items" => [
"list" => [
0 => [
"label" => null,
"value" => "nike",
"count" => 1,
"active" => true,
],
1 => [
"label" => null,
"value" => "rebook",
"count" => 2,
"active" => true,
]
],
"range" => [],
],
],
1 => [
"code" => "color",
"label" => null,
"type" => "list",
"items" => [
"list" => [
0 => [
"label" => null,
"value" => "green",
"count" => 0,
"active" => false,
],
1 => [
"label" => null,
"value" => "red",
"count" => 0,
"active" => false,
],
2 => [
"label" => null,
"value" => "white",
"count" => 3,
"active" => true,
],
],
"range" => [],
],
],
2 => [
"code" => "size",
"label" => null,
"type" => "list",
"items" => [
"list" => [
0 => [
"label" => null,
"count" => 0,
"value" => "43",
"active" => false,
],
1 => [
"label" => null,
"value" => "xl",
"count" => 2,
"active" => true,
],
2 => [
"label" => null,
"value" => "xxl",
"count" => 1,
"active" => true,
],
],
"range" => [],
],
],
3 => [
"code" => "price",
"label" => null,
"type" => "range",
"items" => [
"list" => [],
"range" => [
0 => [
"label" => null,
"count" => 3,
"active" => true,
"fullRange" => [
"min" => 103.0,
"max" => 107.0,
],
"activeRange" => [
"min" => 105.0,
"max" => 107.0,
]
]
]
]
]
]
];
$this->assertEqualsCanonicalizing($expected, FormatData::formatDataWFacets($result));
}
public function testGlobalFilterMinPrice()
{
$filter = [
'price' => [
'key' => 'price',
'lower' => 103,
]
];
$criteria = new Criteria();
$filterCollectionQueryPrice = new FilterGroupCollection([
new Filter(
new Field($filter['price']['key']),
FilterOperator::GTE,
new FilterNumber($filter['price']['lower'])
),
]);
$filterCollectionQueryPrice->setFilterType(FilterType::QUERY);
$criteria->getFilters()->add($filterCollectionQueryPrice);
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => [
's4',
'h1',
'h2',
'h3',
'p1',
],
"facets" => [
0 => [
"code" => "brand",
"label" => null,
"type" => "list",
"items" => [
"list" => [
0 => [
"label" => null,
"value" => "nike",
"count" => 3,
"active" => true,
],
1 => [
"label" => null,
"value" => "rebook",
"count" => 2,
"active" => true,
]
],
"range" => [],
],
],
1 => [
"code" => "color",
"label" => null,
"type" => "list",
"items" => [
"list" => [
0 => [
"label" => null,
"value" => "green",
"count" => 1,
"active" => true,
],
1 => [
"label" => null,
"value" => "red",
"count" => 1,
"active" => true,
],
2 => [
"label" => null,
"value" => "white",
"count" => 3,
"active" => true,
],
],
"range" => [],
],
],
2 => [
"code" => "size",
"label" => null,
"type" => "list",
"items" => [
"list" => [
0 => [
"label" => null,
"count" => 1,
"value" => "43",
"active" => true,
],
1 => [
"label" => null,
"value" => "xl",
"count" => 3,
"active" => true,
],
2 => [
"label" => null,
"value" => "xxl",
"count" => 1,
"active" => true,
],
],
"range" => [],
],
],
3 => [
"code" => "price",
"label" => null,
"type" => "range",
"items" => [
"list" => [],
"range" => [
0 => [
"label" => null,
"count" => 5,
"active" => true,
"fullRange" => [
"min" => 103.0,
"max" => 107.0,
],
"activeRange" => [
"min" => 103.0,
"max" => 107.0,
]
]
]
]
]
]
];
$this->assertEqualsCanonicalizing($expected, FormatData::formatDataWFacets($result));
}
}
<?php
namespace IQDEV\ElasticSearchTests\Filter;
use IQDEV\ElasticSearch\Criteria\Criteria;
use IQDEV\ElasticSearch\Criteria\Filter\Collection\FilterGroupCollection;
use IQDEV\ElasticSearch\Criteria\Filter\Field;
use IQDEV\ElasticSearch\Criteria\Filter\Filter;
use IQDEV\ElasticSearch\Criteria\Filter\FilterOperator;
use IQDEV\ElasticSearch\Criteria\Filter\Value\FilterNumber;
use IQDEV\ElasticSearch\Criteria\Query\SearchQuery;
use IQDEV\ElasticSearchTests\AbstractTestCase;
use IQDEV\ElasticSearchTests\Helpers\FormatData;
use IQDEV\ElasticSearchTests\Service\SearchClient;
class RangeTest extends AbstractTestCase
{
/**
* Поиск элементов по мин цене
*
* @return void
*/
public function testExistByMinPrice(): void
{
$criteria = new Criteria();
$criteria->getFilters()->add(new FilterGroupCollection([
new Filter(
new Field('price'),
FilterOperator::GTE,
new FilterNumber(103)
),
]));
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => [
's4',
'h1',
'h2',
'h3',
'p1'
]
];
$this->assertEqualsCanonicalizing($expected, FormatData::formatData($result));
}
/**
* Поиск элементов по мин цене
*
* @return void
*/
public function testExistByMinPrice2(): void
{
$criteria = new Criteria();
$criteria->getFilters()->add(new FilterGroupCollection([
new Filter(
new Field('price'),
FilterOperator::GT,
new FilterNumber(103.01)
),
]));
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => [
'h1',
'h2',
'h3',
'p1'
]
];
$this->assertEqualsCanonicalizing($expected, FormatData::formatData($result));
}
/**
* Поиск элементов по мин цене
*
* @return void
*/
public function testExistByMinPrice3(): void
{
$criteria = new Criteria();
$criteria->getFilters()->add(new FilterGroupCollection([
new Filter(
new Field('price'),
FilterOperator::GT,
new FilterNumber(102.99)
),
]));
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => [
's4',
'h1',
'h2',
'h3',
'p1'
]
];
$this->assertEqualsCanonicalizing($expected, FormatData::formatData($result));
}
/**
* Поиск элементов по макс цене
*
* @return void
*/
public function testExistByMaxPrice(): void
{
$criteria = new Criteria();
$criteria->getFilters()->add(new FilterGroupCollection([
new Filter(
new Field('price'),
FilterOperator::LTE,
new FilterNumber(102)
),
]));
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => [
's1',
's2',
's3',
]
];
$this->assertEqualsCanonicalizing($expected, FormatData::formatData($result));
}
/**
* Поиск элементов по макс цене
*
* @return void
*/
public function testExistByMaxPrice2(): void
{
$criteria = new Criteria();
$criteria->getFilters()->add(new FilterGroupCollection([
new Filter(
new Field('price'),
FilterOperator::LT,
new FilterNumber(102.99)
),
]));
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => [
's1',
's2',
's3',
]
];
$this->assertEqualsCanonicalizing($expected, FormatData::formatData($result));
}
/**
* Поиск элементов по макс цене
*
* @return void
*/
public function testExistByMaxPrice3(): void
{
$criteria = new Criteria();
$criteria->getFilters()->add(new FilterGroupCollection([
new Filter(
new Field('price'),
FilterOperator::LT,
new FilterNumber(101.99)
),
]));
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => [
's1',
's2',
]
];
$this->assertEqualsCanonicalizing($expected, FormatData::formatData($result));
}
/**
* Поиск элементов по диапазону цен
*
* @return void
*/
public function testExistByRangePrice(): void
{
$criteria = new Criteria();
$criteria->getFilters()->add(new FilterGroupCollection([
new Filter(
new Field('price'),
FilterOperator::GTE,
new FilterNumber(101)
),
new Filter(
new Field('price'),
FilterOperator::LTE,
new FilterNumber(102)
),
]));
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => [
's2',
's3',
]
];
$this->assertEqualsCanonicalizing($expected, FormatData::formatData($result));
}
/**
* Поиск элементов по диапазону цен
*
* @return void
*/
public function testExistByRangePrice2(): void
{
$criteria = new Criteria();
$criteria->getFilters()->add(new FilterGroupCollection([
new Filter(
new Field('price'),
FilterOperator::GTE,
new FilterNumber(101.01)
),
new Filter(
new Field('price'),
FilterOperator::LTE,
new FilterNumber(102)
),
]));
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => [
's3',
]
];
$this->assertEqualsCanonicalizing($expected, FormatData::formatData($result));
}
/**
* Поиск элементов по диапазону цен
*
* @return void
*/
public function testExistByRangePrice3(): void
{
$criteria = new Criteria();
$criteria->getFilters()->add(new FilterGroupCollection([
new Filter(
new Field('price'),
FilterOperator::GTE,
new FilterNumber(101)
),
new Filter(
new Field('price'),
FilterOperator::LTE,
new FilterNumber(101.99)
),
]));
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => [
's2',
]
];
$this->assertEqualsCanonicalizing($expected, FormatData::formatData($result));
}
/**
* Поиск элементов по диапазону цен
*
* @return void
*/
public function testExistByRangePrice4(): void
{
$criteria = new Criteria();
$criteria->getFilters()->add(new FilterGroupCollection([
new Filter(
new Field('price'),
FilterOperator::GTE,
new FilterNumber(101.99)
),
new Filter(
new Field('price'),
FilterOperator::LTE,
new FilterNumber(101.99)
),
]));
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => []
];
$this->assertEquals($expected, FormatData::formatData($result));
}
}
\ No newline at end of file
<?php
namespace IQDEV\ElasticSearchTests\Filter;
use IQDEV\ElasticSearch\Criteria\Criteria;
use IQDEV\ElasticSearch\Criteria\Query\SearchQuery;
use IQDEV\ElasticSearch\Criteria\Search\Search;
use IQDEV\ElasticSearch\Document\Property\Property;
use IQDEV\ElasticSearch\Document\Property\PropertyType;
use IQDEV\ElasticSearchTests\AbstractTestCase;
use IQDEV\ElasticSearchTests\Helpers\FormatData;
use IQDEV\ElasticSearchTests\Service\SearchClient;
class SearchItemsTest extends AbstractTestCase
{
/**
* Поиск всех элементов раздела
*
* @return void
*/
public function testExistByCategory(): void
{
$criteria = new Criteria();
$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));
}
/**
* Поиск всех элементов раздела
*
* @return void
*/
public function testExistByEmptyCategory(): void
{
$criteria = new Criteria();
$criteria->getSearch()->add(
new Search(
new Property('category_id'),
'',
)
);
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => []
];
$this->assertEquals($expected, FormatData::formatData($result));
}
/**
* Поиск всех элементов
*
* @return void
*/
public function testExistAllItems(): void
{
$criteria = new Criteria();
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => [
's1',
's2',
's3',
's4',
'h1',
'h2',
'h3',
'p1'
]
];
$this->assertEqualsCanonicalizing($expected, FormatData::formatData($result));
}
/**
* Поиск существующего элемента по части строки поиска
*
* @return void
*/
public function testExistItemsByPart(): void
{
$criteria = new Criteria();
$criteria->getSearch()->add(
new Search(
new Property('full_search_content', PropertyType::TEXT),
'Nike'
)
);
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => [
's4',
'h1',
'h2',
]
];
$this->assertEqualsCanonicalizing($expected, FormatData::formatData($result));
}
/**
* Поиск существующего элемента по полному названию
*
* @return void
*/
public function testExistItemsByName(): void
{
$criteria = new Criteria();
$criteria->getSearch()->add(
new Search(
new Property('full_search_content', PropertyType::TEXT),
'Nike Dri-FIT Strike',
),
);
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => [
'h1',
'h2',
's4'
]
];
$this->assertEquals($expected, FormatData::formatData($result));
}
/**
* Поиск существующего элемента по полному названию
*
* @return void
*/
public function testExistItemsByCyrillicName(): void
{
$criteria = new Criteria();
$criteria->getSearch()->add(
new Search(
new Property('full_search_content', PropertyType::TEXT),
'Товар с ценой',
),
);
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => [
'p1',
]
];
$this->assertEqualsCanonicalizing($expected, FormatData::formatData($result));
}
}
<?php
namespace IQDEV\ElasticSearchTests\Filter;
use IQDEV\ElasticSearch\Criteria\Criteria;
use IQDEV\ElasticSearch\Criteria\Order\OrderDirection;
use IQDEV\ElasticSearch\Criteria\Order\OrderFactory;
use IQDEV\ElasticSearch\Criteria\Query\SearchQuery;
use IQDEV\ElasticSearch\Document\Property\Property;
use IQDEV\ElasticSearch\Document\Property\PropertyType;
use IQDEV\ElasticSearchTests\AbstractTestCase;
use IQDEV\ElasticSearchTests\Helpers\FormatData;
use IQDEV\ElasticSearchTests\Service\SearchClient;
class SortTest extends AbstractTestCase
{
/**
* Сортировка элементов по категории
*
* @return void
*/
public function testSortByCategory(): void
{
$criteria = new Criteria();
$criteria->getSorting()->add(
OrderFactory::createByProperty(new Property('category_id'), OrderDirection::ASC)
);
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => [
'p1',
's1',
's2',
's3',
's4',
'h1',
'h2',
'h3',
]
];
$this->assertEquals($expected, FormatData::formatData($result));
}
/**
* Обратная сортировка элементов по категории
*
* @return void
*/
public function testSortByCategoryReverse(): void
{
$criteria = new Criteria();
$criteria->getSorting()->add(
OrderFactory::createByProperty(new Property('category_id'), OrderDirection::DESC)
);
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => [
'h1',
'h2',
'h3',
's1',
's2',
's3',
's4',
'p1',
]
];
$this->assertEquals($expected, FormatData::formatData($result));
}
/**
* Сортировка элементов по свойству
*
* @return void
*/
public function testSortByKeyword(): void
{
$criteria = new Criteria();
$criteria->getSorting()->add(
OrderFactory::createByProperty(new Property('color', PropertyType::KEYWORD), OrderDirection::ASC)
);
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => [
's3',
's1',
's4',
's2',
'h1',
'h2',
'h3',
'p1'
]
];
$this->assertEquals($expected, FormatData::formatData($result));
}
/**
* Сортировка элементов по свойству
*
* @return void
*/
public function testSortByKeywordReverse(): void
{
$criteria = new Criteria();
$criteria->getSorting()->add(
OrderFactory::createByProperty(new Property('color', PropertyType::KEYWORD), OrderDirection::DESC)
);
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => [
'h2',
'h3',
'p1',
's2',
'h1',
's1',
's4',
's3',
]
];
$this->assertEquals($expected, FormatData::formatData($result));
}
/**
* Сортировка элементов по свойству
*
* @return void
*/
public function testSortByNumber(): void
{
$criteria = new Criteria();
$criteria->getSorting()->add(
OrderFactory::createByProperty(new Property('price', PropertyType::NUMBER), OrderDirection::ASC)
);
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => [
's1',
's2',
's3',
's4',
'h1',
'h2',
'h3',
'p1'
]
];
$this->assertEquals($expected, FormatData::formatData($result));
}
/**
* Сортировка элементов по свойству
*
* @return void
*/
public function testSortByNumberReverse(): void
{
$criteria = new Criteria();
$criteria->getSorting()->add(
OrderFactory::createByProperty(new Property('price', PropertyType::NUMBER), OrderDirection::DESC)
);
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => [
'p1',
'h3',
'h2',
'h1',
's4',
's3',
's2',
's1',
]
];
$this->assertEquals($expected, FormatData::formatData($result));
}
/**
* Сортировка элементов по свойству
*
* @return void
*/
public function testSortByCombined(): void
{
$criteria = new Criteria();
$criteria->getSorting()->add(
OrderFactory::createByProperty(new Property('size', PropertyType::KEYWORD), OrderDirection::ASC)
);
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => [
's4',
's1',
's2',
's3',
'h1',
'h3',
'p1',
'h2',
]
];
$this->assertEquals($expected, FormatData::formatData($result));
}
/**
* Сортировка элементов по свойству
*
* @return void
*/
public function testSortByCombinedReverse(): void
{
$criteria = new Criteria();
$criteria->getSorting()->add(
OrderFactory::createByProperty(new Property('size', PropertyType::KEYWORD), OrderDirection::DESC)
);
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => [
'h2',
'h1',
'h3',
'p1',
's2',
's3',
's1',
's4',
]
];
$this->assertEquals($expected, FormatData::formatData($result));
}
}
\ No newline at end of file
<?php
declare(strict_types=1);
namespace IQDEV\ElasticSearchTests\Filter;
use IQDEV\ElasticSearch\Criteria\Criteria;
use IQDEV\ElasticSearch\Criteria\Filter\Collection\FilterGroupCollection;
use IQDEV\ElasticSearch\Criteria\Filter\Field;
use IQDEV\ElasticSearch\Criteria\Filter\Filter;
use IQDEV\ElasticSearch\Criteria\Filter\FilterOperator;
use IQDEV\ElasticSearch\Criteria\Filter\LogicOperator;
use IQDEV\ElasticSearch\Criteria\Filter\Value\FilterKeyword;
use IQDEV\ElasticSearch\Criteria\Query\SearchQuery;
use IQDEV\ElasticSearch\Criteria\Search\Search;
use IQDEV\ElasticSearch\Document\Property\Property;
use IQDEV\ElasticSearchTests\AbstractTestCase;
use IQDEV\ElasticSearchTests\Helpers\FormatData;
use IQDEV\ElasticSearchTests\Service\SearchClient;
class UpdatedSearchTest extends AbstractTestCase
{
/**
* Поиск по свойству nested
*
* @return void
*/
public function testSearchByNestedProperty(): void
{
$criteria = new Criteria();
$criteria->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));
}
public function testMustNotNestedFilter(): void
{
$criteria = new Criteria();
$group = new FilterGroupCollection([
new Filter(
new Field('brand'),
FilterOperator::EQ,
new FilterKeyword('adidas'),
)
]);
$group->setLogicOperator(LogicOperator::NOT);
$criteria->getFilters()->add($group);
$q = new SearchQuery($criteria);
$handler = SearchClient::getInstance();
$result = $handler->handle($q)->result;
$expected = [
'hits' => [
's3',
's4',
'h1',
'h2',
'h3',
'p1',
]
];
$this->assertEqualsCanonicalizing($expected, FormatData::formatData($result));
}
public function testMustNotPropertyFilter(): void
{
$criteria = new Criteria();
$group = new FilterGroupCollection([
new Filter(
new Field('category_id'),
FilterOperator::EQ,
new FilterKeyword('prices'),
)
]);
$group->setLogicOperator(LogicOperator::NOT);
$criteria->getFilters()->add($group);
$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));
}
}
<?php
namespace IQDEV\ElasticSearchTests\Helpers;
class Arr
{
/**
* Flatten a multi-dimensional associative array with dots.
* @param array $array
* @param $prepend
* @return array
*/
public static function dot(array $array, $prepend = ''): array
{
$results = [];
foreach ($array as $key => $value) {
if (is_array($value) && ! empty($value)) {
$results = array_merge($results, static::dot($value, $prepend.$key.'.'));
} else {
$results[$prepend.$key] = $value;
}
}
return $results;
}
}
\ No newline at end of file
<?php
namespace IQDEV\ElasticSearchTests\Helpers;
use IQDEV\ElasticSearch\Document\Product;
use IQDEV\ElasticSearch\Facet\FacetResult;
use IQDEV\ElasticSearch\Facet\Item\FacetItemList;
use IQDEV\ElasticSearch\Facet\Item\FacetItemRange;
use IQDEV\ElasticSearch\Result;
class FormatData
{
public static function formatData(Result $result): array
{
$oProductCollection = $result->getProducts();
$aResult = ['hits' => []];
foreach ($oProductCollection as $oProduct) {
/** @var Product $oProduct */
$aResult['hits'][] = $oProduct->id;
}
return $aResult;
}
public static function formatDataWFacets(Result $result): array
{
$aResult = ['facets' => []];
$aResult['hits'] = static::formatData($result)['hits'];
foreach ($result->getFacets() as $facet) {
/** @var FacetResult $facet */
$dataFacet = [
'code' => $facet->getCode(),
'label' => null, // $facet->getLabel(),
'type' => $facet->getType()->value,
'items' => [
'list' => [],
'range' => []
],
];
$items = $facet->products->sort('getValue');
foreach ($items as $item) {
if ($item instanceof FacetItemList) {
/** @var FacetItemList $item */
$dataFacet['items']['list'][] = [
'label' => $item->getLabel(),
'value' => $item->getValue(),
'count' => $item->getCount(),
'active' => $item->isActive(),
];
}
if ($item instanceof FacetItemRange) {
/** @var FacetItemRange $item */
$aData = [
'label' => $item->getLabel(),
'count' => $item->getCount(),
'active' => $item->isActive(),
];
$aData['fullRange'] = $item->getFullRange();
$aData['activeRange'] = $item->getSelectedRange();
if ($result->getTotal() > 0 && empty(array_filter($aData['activeRange']))) {
$aData['activeRange'] = $aData['fullRange'];
}
$dataFacet['items']['range'][] = $aData;
}
}
$aResult['facets'][] = $dataFacet;
}
return $aResult;
}
public static function formatDataProducts(Result $result): array
{
$products = [];
/** @var Product $product */
foreach ($result->getProducts() as $product) {
$data = [
'id' => $product->id,
'category' => $product->info['category_id']
];
if ($product->title) {
$data['name'] = $product->title;
}
if (isset($product->info['search_data'])) {
$props = $product->info['search_data'];
if (!empty($props['keyword_facet'])) {
foreach ($props['keyword_facet'] as $prop) {
$data['properties'][$prop['facet_code']] = $prop['facet_value'];
}
}
if (!empty($props['number_facet'])) {
foreach ($props['number_facet'] as $prop) {
$data['properties'][$prop['facet_code']] = $prop['facet_value'];
}
}
}
$products[] = $data;
}
return ['products' => $products];
}
}
\ No newline at end of file
<?php
namespace IQDEV\ElasticSearchTests\Helpers;
use IQDEV\ElasticSearch\Configuration;
use IQDEV\ElasticSearch\Document\ProductDocument;
use IQDEV\ElasticSearch\Document\Property\Property;
use IQDEV\ElasticSearch\Document\Property\PropertyType;
use IQDEV\ElasticSearch\Facet\FacetFactory;
use IQDEV\ElasticSearch\Indexer\AddIndex;
use IQDEV\ElasticSearch\Indexer\DeleteIndex;
use IQDEV\ElasticSearch\Indexer\IndexProvider;
use IQDEV\ElasticSearch\Indexer\UpdateIndex;
class TestIndexProvider implements IndexProvider
{
private Configuration $configuration;
private array $products = [];
public function __construct(Configuration $configuration, array $products)
{
$this->configuration = $configuration;
$this->products = $products;
}
/**
* @inheritDoc
*/
public function get(): \Generator
{
foreach ($this->products as $product) {
$document = new ProductDocument(
FacetFactory::createFromProperty(new Property('category_id', PropertyType::BASE), $product['category'])
);
//todo по-хорошему нужны базовые классы, которые будут описывать свойства
// и формировать структуру для последующей обработки
$data = [
'id' => $product['id'],
];
if (isset($product['name'])) {
$document->setSearchContent($product['name']);
$data['title'] = $product['name'];
}
$document->setAdditionData($data);
if (isset($product['properties'])) {
foreach ($product['properties'] as $key => $value) {
if ($key === 'price') {
$document->getNumberFacets()->add(
FacetFactory::createFromProperty(new Property($key, PropertyType::NUMBER), $value)
);
} else {
$document->getKeywordFacets()->add(
FacetFactory::createFromProperty(new Property($key, PropertyType::KEYWORD), $value)
);
}
}
}
$document->setByConfiguration($this->configuration, 'new', $product['new']);
$document->setByConfiguration($this->configuration, 'rating', $product['rating']);
$product['type'] = $product['type'] ?? null;
switch ($product['type']) {
case 'update':
$document->skipEmpty(true);
$index = new UpdateIndex(
$this->configuration->getIndexName(),
$document,
$product['id']
);
break;
case 'delete':
$index = new DeleteIndex(
$this->configuration->getIndexName(),
$product['id']
);
break;
default:
$index = new AddIndex(
$this->configuration->getIndexName(),
$document,
$product['id']
);
break;
}
yield $index;
}
}
/**
* @inheritDoc
*/
public function setBatchSize(int $size): void
{
}
/**
* @inheritDoc
*/
public function getBatchSize(): ?int
{
return null;
}
/**
* @inheritDoc
*/
public function setLimit(int $limit): void
{
}
/**
* @inheritDoc
*/
public function getLimit(): ?int
{
return null;
}
}
<?php
namespace IQDEV\ElasticSearchTests\Seed;
use IQDEV\ElasticSearch\Config\BaseConfiguration;
use IQDEV\ElasticSearch\Configuration;
use IQDEV\ElasticSearch\Indexer\IndexRunner;
use IQDEV\ElasticSearchTests\Factory\ClientFactory;
use IQDEV\ElasticSearchTests\Helpers\TestIndexProvider;
use Psr\Log\NullLogger;
class DefaultSeed
{
private IndexRunner $indexRunner;
private Configuration $configuration;
public function __construct()
{
$this->configuration = new BaseConfiguration();
$this->indexRunner = new IndexRunner(
ClientFactory::create(),
$this->configuration,
new NullLogger()
);
}
public function start()
{
$provider = new TestIndexProvider($this->configuration, [
[
'id' => 's1',
'name' => 'Кроссовки NMD_R1 Boba Fett Spectoo',
'category' => 'shoes',
'properties' => ['brand' => 'adidas', 'color' => 'green', 'size' => 46,'price' => 100],
'year' => 2014,
'new' => false,
'rating' => 3,
],
[
'id' => 's2',
'name' => 'КРОССОВКИ ULTRABOOST 5.0 DNA',
'category' => 'shoes',
'properties' => ['brand' => 'adidas', 'color' => 'red', 'size' => 47,'price' => 101],
'year' => 2023,
'new' => true,
'rating' => 3,
],
[
'id' => 's3',
'name' => 'Кроссовки Reebok Royal Techque',
'category' => 'shoes',
'properties' => ['brand' => 'rebook', 'color' => 'blue', 'size' => 47,'price' => 102],
'year' => 1980,
'new' => false,
'rating' => 3,
],
[
'id' => 's4',
'name' => 'Nike Air Zoom Pegasus 39',
'category' => 'shoes',
'properties' => ['brand' => 'nike', 'color' => 'green', 'size' => 43,'price' => 103],
'year' => 2014,
'new' => true,
'rating' => 5,
],
[
'id' => 'h1',
'name' => 'Nike Dri-FIT Strike',
'category' => 't-short',
'properties' => ['brand' => 'nike', 'color' => 'red', 'size' => 'xl','price' => 104],
'year' => 2010,
'new' => true,
'rating' => 4,
],
[
'id' => 'h2',
'name' => 'Nike Dri-FIT Rise 365',
'category' => 't-short',
'properties' => ['brand' => 'nike', 'color' => 'white', 'size' => 'xxl','price' => 105],
'year' => 2000,
'new' => true,
'rating' => 3,
],
[
'id' => 'h3',
'name' => 'Компрессионная Футболка ACTIVCHILL Graphic Move',
'category' => 't-short',
'properties' => ['brand' => 'rebook', 'color' => 'white', 'size' => 'xl','price' => 106],
'year' => 1990,
'new' => true,
'rating' => 3,
],
[
'id' => 'p1',
'name' => 'Товар с ценой',
'category' => 'prices',
'properties' => ['brand' => 'rebook', 'color' => 'white', 'size' => 'xl','price' => 107],
'year' => 2015,
'new' => false,
'rating' => 3,
],
]);
$this->indexRunner->run($provider);
}
}