Skip to content
Snippets Groups Projects
Commit ca81b1db authored by Vadim Galizyanov's avatar Vadim Galizyanov
Browse files

fixing a bug with updating a document

parent f88ddc5c
No related branches found
No related tags found
No related merge requests found
......@@ -20,5 +20,6 @@
</coverage>
<php>
<env name="IQ_ES_PRODUCT_SEARCH_INDEX" value="product-test"/>
<env name="IQ_ES_PRODUCT_SEARCH_INDEX_CHANGING_STATE" value="product-test-changing-state"/>
</php>
</phpunit>
\ No newline at end of file
......@@ -15,12 +15,14 @@ class ArrayHelper
public static function array_filter_recursive(array $array, ?callable $callback = null): array
{
$array = is_callable($callback) ? array_filter($array, $callback) : array_filter($array);
foreach ($array as &$value) {
foreach ($array as $key => &$value) {
if (is_array($value)) {
$value = call_user_func([__CLASS__, __FUNCTION__], $value, $callback);
if (!empty($value)) {
$value = self::array_filter_recursive($value, $callback);
} else {
unset($array[$key]);
}
}
}
......
......@@ -74,11 +74,15 @@ final class IndexRunner
continue;
}
if (!($index instanceof AddIndex) && !($index instanceof UpdateIndex)) {
if ($index instanceof AddIndex) {
$this->esClient->index($index->es());
continue;
}
$this->esClient->index($index->es());
if ($index instanceof UpdateIndex) {
$this->esClient->update($index->es());
continue;
}
}
}
}
......
<?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\Filter;
use Elastic\Elasticsearch\Client;
use IQDEV\ElasticSearch\Configuration;
use IQDEV\ElasticSearch\Converter\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\Test\TestLogger;
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 TestLogger()
);
}
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);
unset($updateData['type']);
$expected = [
'products' => [
array_merge($this->product, $updateData)
]
];
$this->assertEqualsCanonicalizing($expected, FormatData::formatDataProducts($result));
}
}
\ No newline at end of file
......@@ -74,4 +74,37 @@ class FormatData
}
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\Facet\FacetCategory;
use IQDEV\ElasticSearch\Facet\FacetKeyword;
use IQDEV\ElasticSearch\Facet\FacetNumber;
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(new FacetCategory($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 => $prop) {
if ($key === 'price') {
$document->getNumberFacets()->add(new FacetNumber($key, $prop));
} else {
$document->getKeywordFacets()->add(new FacetKeyword($key, $prop));
}
}
}
$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;
}
}
\ No newline at end of file
......@@ -4,14 +4,9 @@ namespace IQDEV\ElasticSearchTests\Seed;
use IQDEV\ElasticSearch\Config\BaseConfiguration;
use IQDEV\ElasticSearch\Configuration;
use IQDEV\ElasticSearch\Document\ProductDocument;
use IQDEV\ElasticSearch\Facet\FacetCategory;
use IQDEV\ElasticSearch\Facet\FacetKeyword;
use IQDEV\ElasticSearch\Facet\FacetNumber;
use IQDEV\ElasticSearch\Indexer\AddIndex;
use IQDEV\ElasticSearch\Indexer\IndexProvider;
use IQDEV\ElasticSearch\Indexer\IndexRunner;
use IQDEV\ElasticSearchTests\Factory\ClientFactory;
use IQDEV\ElasticSearchTests\Helpers\TestIndexProvider;
use Psr\Log\Test\TestLogger;
class DefaultSeed
......@@ -33,105 +28,56 @@ class DefaultSeed
public function start()
{
$provider = new class implements IndexProvider {
public function get(): \Generator
{
$products = [
[
'id' => 's1',
'name' => 'Кроссовки NMD_R1 Boba Fett Spectoo',
'category' => 'shoes',
'properties' => ['brand' => 'adidas', 'color' => 'green', 'size' => 46,'price' => 100]
],
[
'id' => 's2',
'name' => 'КРОССОВКИ ULTRABOOST 5.0 DNA',
'category' => 'shoes',
'properties' => ['brand' => 'adidas', 'color' => 'red', 'size' => 47,'price' => 101]
],
[
'id' => 's3',
'name' => 'Кроссовки Reebok Royal Techque',
'category' => 'shoes',
'properties' => ['brand' => 'rebook', 'color' => 'blue', 'size' => 47,'price' => 102]
],
[
'id' => 's4',
'name' => 'Nike Air Zoom Pegasus 39',
'category' => 'shoes',
'properties' => ['brand' => 'nike', 'color' => 'green', 'size' => 43,'price' => 103]
],
[
'id' => 'h1',
'name' => 'Nike Dri-FIT Strike',
'category' => 't-short',
'properties' => ['brand' => 'nike', 'color' => 'red', 'size' => 'xl','price' => 104]
],
[
'id' => 'h2',
'name' => 'Nike Dri-FIT Rise 365',
'category' => 't-short',
'properties' => ['brand' => 'nike', 'color' => 'white', 'size' => 'xxl','price' => 105]
],
[
'id' => 'h3',
'name' => 'Компрессионная Футболка ACTIVCHILL Graphic Move',
'category' => 't-short',
'properties' => ['brand' => 'rebook', 'color' => 'white', 'size' => 'xl','price' => 106]
],
[
'id' => 'p1',
'name' => 'Товар с ценой',
'category' => 'prices',
'properties' => ['brand' => 'rebook', 'color' => 'white', 'size' => 'xl','price' => 107]
],
];
foreach ($products as $product) {
$document = new ProductDocument(new FacetCategory($product['category']));
//todo по-хорошему нужны базовые классы, которые будут описывать свойства
// и формировать структуру для последующей обработки
$document->setAdditionData([
'id' => $product['id'],
'title' => $product['name'],
]);
foreach ($product['properties'] as $key => $prop) {
if ($key === 'price') {
$document->getNumberFacets()->add(new FacetNumber($key, $prop));
} else {
$document->getKeywordFacets()->add(new FacetKeyword($key, $prop));
}
}
$document->setSearchContent($product['name']);
yield new AddIndex(
$_ENV['IQ_ES_PRODUCT_SEARCH_INDEX'],
$document,
$product['id']
);
}
}
public function setBatchSize(int $size): void
{
}
public function getBatchSize(): ?int
{
return null;
}
public function setLimit(int $limit): void
{
}
public function getLimit(): ?int
{
return null;
}
};
$provider = new TestIndexProvider([
[
'id' => 's1',
'name' => 'Кроссовки NMD_R1 Boba Fett Spectoo',
'category' => 'shoes',
'properties' => ['brand' => 'adidas', 'color' => 'green', 'size' => 46,'price' => 100]
],
[
'id' => 's2',
'name' => 'КРОССОВКИ ULTRABOOST 5.0 DNA',
'category' => 'shoes',
'properties' => ['brand' => 'adidas', 'color' => 'red', 'size' => 47,'price' => 101]
],
[
'id' => 's3',
'name' => 'Кроссовки Reebok Royal Techque',
'category' => 'shoes',
'properties' => ['brand' => 'rebook', 'color' => 'blue', 'size' => 47,'price' => 102]
],
[
'id' => 's4',
'name' => 'Nike Air Zoom Pegasus 39',
'category' => 'shoes',
'properties' => ['brand' => 'nike', 'color' => 'green', 'size' => 43,'price' => 103]
],
[
'id' => 'h1',
'name' => 'Nike Dri-FIT Strike',
'category' => 't-short',
'properties' => ['brand' => 'nike', 'color' => 'red', 'size' => 'xl','price' => 104]
],
[
'id' => 'h2',
'name' => 'Nike Dri-FIT Rise 365',
'category' => 't-short',
'properties' => ['brand' => 'nike', 'color' => 'white', 'size' => 'xxl','price' => 105]
],
[
'id' => 'h3',
'name' => 'Компрессионная Футболка ACTIVCHILL Graphic Move',
'category' => 't-short',
'properties' => ['brand' => 'rebook', 'color' => 'white', 'size' => 'xl','price' => 106]
],
[
'id' => 'p1',
'name' => 'Товар с ценой',
'category' => 'prices',
'properties' => ['brand' => 'rebook', 'color' => 'white', 'size' => 'xl','price' => 107]
],
]);
$this->indexRunner->run($provider);
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment