From a2a1012e86876943a30a23978573d38c3228854a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gracjan=20J=C3=B3zefczyk?= Date: Thu, 6 Jun 2024 11:40:34 +0200 Subject: [PATCH 1/8] OP-303: Enable api --- tests/Application/config/packages/_sylius.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/Application/config/packages/_sylius.yaml b/tests/Application/config/packages/_sylius.yaml index 7532b01a..18acdd44 100644 --- a/tests/Application/config/packages/_sylius.yaml +++ b/tests/Application/config/packages/_sylius.yaml @@ -13,3 +13,6 @@ parameters: sylius_shop: product_grid: include_all_descendants: true + +sylius_api: + enabled: true From 94f1763cea5a8981fbd52b2cf9db2e619af23a18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gracjan=20J=C3=B3zefczyk?= Date: Thu, 6 Jun 2024 11:41:23 +0200 Subject: [PATCH 2/8] OP-303: API facets resolver --- src/Api/Resolver/FacetsResolver.php | 44 +++++++++++++++++++ src/Api/Resolver/FacetsResolverInterface.php | 10 +++++ .../config/services/api/resolver.xml | 12 +++++ 3 files changed, 66 insertions(+) create mode 100644 src/Api/Resolver/FacetsResolver.php create mode 100644 src/Api/Resolver/FacetsResolverInterface.php create mode 100644 src/Resources/config/services/api/resolver.xml diff --git a/src/Api/Resolver/FacetsResolver.php b/src/Api/Resolver/FacetsResolver.php new file mode 100644 index 00000000..44af3364 --- /dev/null +++ b/src/Api/Resolver/FacetsResolver.php @@ -0,0 +1,44 @@ +autoDiscoverRegistry->autoRegister(); + + $boolQuery = $this->queryBuilder->buildQuery($data); + $query = new Query($boolQuery); + $query->setSize(0); + + foreach ($this->facetRegistry->getFacets() as $facetId => $facet) { + $query->addAggregation($facet->getAggregation()->setName($facetId)); + } + + $facets = $this->finder->findPaginated($query); + $adapter = $facets->getAdapter(); + if (!$adapter instanceof FantaPaginatorAdapter) { + return []; + } + + return $adapter->getAggregations(); + } +} diff --git a/src/Api/Resolver/FacetsResolverInterface.php b/src/Api/Resolver/FacetsResolverInterface.php new file mode 100644 index 00000000..3be5408c --- /dev/null +++ b/src/Api/Resolver/FacetsResolverInterface.php @@ -0,0 +1,10 @@ + + + + + + + + + + + + From 39c18d1d72c0b0cfbf13441659b2b4c02281c3e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gracjan=20J=C3=B3zefczyk?= Date: Thu, 6 Jun 2024 11:42:01 +0200 Subject: [PATCH 3/8] OP-303: Handle API request --- .../RequestDataHandler/RequestDataHandler.php | 28 +++++++++++++++++++ .../RequestDataHandlerInterface.php | 10 +++++++ .../services/api/request_data_handler.xml | 10 +++++++ 3 files changed, 48 insertions(+) create mode 100644 src/Api/RequestDataHandler/RequestDataHandler.php create mode 100644 src/Api/RequestDataHandler/RequestDataHandlerInterface.php create mode 100644 src/Resources/config/services/api/request_data_handler.xml diff --git a/src/Api/RequestDataHandler/RequestDataHandler.php b/src/Api/RequestDataHandler/RequestDataHandler.php new file mode 100644 index 00000000..04719b5b --- /dev/null +++ b/src/Api/RequestDataHandler/RequestDataHandler.php @@ -0,0 +1,28 @@ +sortDataHandler->retrieveData($requestData), + $this->paginationDataHandler->retrieveData($requestData), + ['query' => $requestData['query'] ?? ''], + ['facets' => $requestData['facets'] ?? []], + ); + } +} diff --git a/src/Api/RequestDataHandler/RequestDataHandlerInterface.php b/src/Api/RequestDataHandler/RequestDataHandlerInterface.php new file mode 100644 index 00000000..33189d34 --- /dev/null +++ b/src/Api/RequestDataHandler/RequestDataHandlerInterface.php @@ -0,0 +1,10 @@ + + + + + + + + + + From 3dac705b55271e680b6dafbb237171cf1643d505 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gracjan=20J=C3=B3zefczyk?= Date: Thu, 6 Jun 2024 11:42:46 +0200 Subject: [PATCH 4/8] OP-303: Expose API resource --- .../ProductCollectionDataProvider.php | 54 ++++ .../config/api_resources/Product.xml | 251 ++++++++++++++++++ .../config/services/api/data_provider.xml | 12 + 3 files changed, 317 insertions(+) create mode 100644 src/Api/DataProvider/ProductCollectionDataProvider.php create mode 100644 src/Resources/config/api_resources/Product.xml create mode 100644 src/Resources/config/services/api/data_provider.xml diff --git a/src/Api/DataProvider/ProductCollectionDataProvider.php b/src/Api/DataProvider/ProductCollectionDataProvider.php new file mode 100644 index 00000000..4e2afc8d --- /dev/null +++ b/src/Api/DataProvider/ProductCollectionDataProvider.php @@ -0,0 +1,54 @@ +dataHandler->retrieveData($context); + $facets = $this->facetsResolver->resolve($data); + $products = $this->shopProductsFinder->find($data); + + return [ + 'items' => $products->jsonSerialize(), + 'facets' => $facets, + 'pagination' => [ + 'current_page' => $products->getCurrentPage(), + 'has_previous_page' => $products->hasPreviousPage(), + 'has_next_page' => $products->hasNextPage(), + 'per_page' => $products->getMaxPerPage(), + 'total_items' => $products->getNbResults(), + 'total_pages' => $products->getNbPages(), + ], + ]; + } + + public function supports( + string $resourceClass, + string $operationName = null, + array $context = [] + ): bool { + return self::SUPPORTED_OPERATION_TYPE === $operationName; + } +} diff --git a/src/Resources/config/api_resources/Product.xml b/src/Resources/config/api_resources/Product.xml new file mode 100644 index 00000000..30f76346 --- /dev/null +++ b/src/Resources/config/api_resources/Product.xml @@ -0,0 +1,251 @@ + + + + + sylius + + + ASC + + + + + GET + /shop/products/search + false + + + shop:product:index + sylius:shop:product:index + + + + + + query + query + false + + string + + Search query + + + limit + query + false + + integer + 10 + + Number of items to return per page + + + page + query + false + + integer + 1 + + Page number + + + order_by + query + false + + string + + sold_units + product_created_at + price + + + Field to order by (sold_units, product_created_at, price) + + + sort + query + false + + string + + asc + desc + + + Order direction (asc, desc) + + + facets + query + false + deepObject + true + Filter facets with dynamic keys. Example: facets[t_shirt_material][]=100%25_cotton&facets[t_shirt_brand][]=modern_wear + + + + + Successful response + + + + object + + + array + + object + + + array + + string + + + + string + + + integer + + + array + + object + + + integer + + + string + + + string + + + + + + integer + + + string + + + array + + string + + + + array + + string + + + + array + + string + + + + string + date-time + + + string + date-time + + + string + + + array + + array + + + + string + + + string + + + string + + + + + + object + + object + + + integer + + + integer + + + array + + object + + + string + + + integer + + + + + + + + + object + + + integer + + + boolean + + + boolean + + + integer + + + integer + + + integer + + + + + + + + + + + + + + + + + diff --git a/src/Resources/config/services/api/data_provider.xml b/src/Resources/config/services/api/data_provider.xml new file mode 100644 index 00000000..66702d1e --- /dev/null +++ b/src/Resources/config/services/api/data_provider.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + From 61f3b4c1d87a934c0ebdd6b8b861fb43e06fe421 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gracjan=20J=C3=B3zefczyk?= Date: Thu, 6 Jun 2024 14:27:51 +0200 Subject: [PATCH 5/8] OP-303: Add API tests --- .../Integration/Api/ProductListingTest.php | 42 ++++++++++ .../Api/test_it_finds_products_by_name.yaml | 46 +++++++++++ ..._it_finds_products_by_name_and_facets.yaml | 79 +++++++++++++++++++ .../Integration/IntegrationTestCase.php | 3 +- .../test_it_finds_products_by_name.json | 47 +++++++++++ ..._it_finds_products_by_name_and_facets.json | 57 +++++++++++++ 6 files changed, 273 insertions(+), 1 deletion(-) create mode 100644 tests/PHPUnit/Integration/Api/ProductListingTest.php create mode 100644 tests/PHPUnit/Integration/DataFixtures/ORM/Api/test_it_finds_products_by_name.yaml create mode 100644 tests/PHPUnit/Integration/DataFixtures/ORM/Api/test_it_finds_products_by_name_and_facets.yaml create mode 100644 tests/PHPUnit/Integration/Responses/Expected/test_it_finds_products_by_name.json create mode 100644 tests/PHPUnit/Integration/Responses/Expected/test_it_finds_products_by_name_and_facets.json diff --git a/tests/PHPUnit/Integration/Api/ProductListingTest.php b/tests/PHPUnit/Integration/Api/ProductListingTest.php new file mode 100644 index 00000000..2752df13 --- /dev/null +++ b/tests/PHPUnit/Integration/Api/ProductListingTest.php @@ -0,0 +1,42 @@ +loadFixturesFromFiles(['Api/test_it_finds_products_by_name.yaml']); + $this->populateElasticsearch(); + + $this->client->request('GET', '/api/v2/shop/products/search?query=mug'); + $response = $this->client->getResponse(); + $this->assertResponse($response, 'test_it_finds_products_by_name', Response::HTTP_OK); + } + + public function test_it_finds_products_by_name_and_facets(): void + { + $this->loadFixturesFromFiles(['Api/test_it_finds_products_by_name_and_facets.yaml']); + $this->populateElasticsearch(); + + $this->client->request('GET', '/api/v2/shop/products/search?query=mug&facets[color][]=red'); + $response = $this->client->getResponse(); + $this->assertResponse($response, 'test_it_finds_products_by_name_and_facets', Response::HTTP_OK); + } + + private function populateElasticsearch(): void + { + $process = new Process(['tests/Application/bin/console', 'fos:elastica:populate']); + $process->run(); + + if (!$process->isSuccessful()) { + throw new \Exception('Failed to populate Elasticsearch: ' . $process->getErrorOutput()); + } + } +} diff --git a/tests/PHPUnit/Integration/DataFixtures/ORM/Api/test_it_finds_products_by_name.yaml b/tests/PHPUnit/Integration/DataFixtures/ORM/Api/test_it_finds_products_by_name.yaml new file mode 100644 index 00000000..83f5307e --- /dev/null +++ b/tests/PHPUnit/Integration/DataFixtures/ORM/Api/test_it_finds_products_by_name.yaml @@ -0,0 +1,46 @@ +Sylius\Component\Core\Model\Channel: + channel_web: + code: 'WEB' + name: 'Web Channel' + hostname: 'localhost' + description: 'Lorem ipsum' + baseCurrency: '@currency_usd' + defaultLocale: '@locale_en' + locales: ['@locale_en'] + color: 'black' + enabled: true + taxCalculationStrategy: 'order_items_based' + +Sylius\Component\Currency\Model\Currency: + currency_usd: + code: 'USD' + +Sylius\Component\Locale\Model\Locale: + locale_en: + code: 'en_US' + +Sylius\Component\Core\Model\Product: + product_mug: + code: 'MUG' + channels: ['@channel_web'] + currentLocale: 'en_US' + translations: + en_US: '@product_translation_mug' + +Sylius\Component\Core\Model\ProductTranslation: + product_translation_mug: + slug: 'mug' + locale: 'en_US' + name: 'Mug' + description: '' + translatable: '@product_mug' + +Sylius\Component\Core\Model\Taxon: + mugs: + code: "mugs" + +Sylius\Component\Core\Model\ProductTaxon: + productTaxon1: + product: "@product_mug" + taxon: "@mugs" + position: 0 diff --git a/tests/PHPUnit/Integration/DataFixtures/ORM/Api/test_it_finds_products_by_name_and_facets.yaml b/tests/PHPUnit/Integration/DataFixtures/ORM/Api/test_it_finds_products_by_name_and_facets.yaml new file mode 100644 index 00000000..ef5b671d --- /dev/null +++ b/tests/PHPUnit/Integration/DataFixtures/ORM/Api/test_it_finds_products_by_name_and_facets.yaml @@ -0,0 +1,79 @@ +Sylius\Component\Core\Model\Channel: + channel_web: + code: 'WEB' + name: 'Web Channel' + hostname: 'localhost' + description: 'Lorem ipsum' + baseCurrency: '@currency_usd' + defaultLocale: '@locale_en' + locales: ['@locale_en'] + color: 'black' + enabled: true + taxCalculationStrategy: 'order_items_based' + +Sylius\Component\Currency\Model\Currency: + currency_usd: + code: 'USD' + +Sylius\Component\Locale\Model\Locale: + locale_en: + code: 'en_US' + +Sylius\Component\Core\Model\Product: + product_mug: + code: 'MUG' + channels: ['@channel_web'] + currentLocale: 'en_US' + translations: + en_US: '@product_translation_mug' + product_mug2: + code: 'MUG2' + channels: ['@channel_web'] + currentLocale: 'en_US' + translations: + en_US: '@product_translation_mug2' + +Sylius\Component\Core\Model\ProductTranslation: + product_translation_mug: + slug: 'mug' + locale: 'en_US' + name: 'Mug' + description: '' + translatable: '@product_mug' + product_translation_mug2: + slug: 'mug-2' + locale: 'en_US' + name: 'Mug 2' + description: '' + translatable: '@product_mug2' + +Sylius\Component\Product\Model\ProductAttributeTranslation: + attributeTranslation1: + locale: en_US + name: "Product color" + translatable: "@product_attribute_color" + +Sylius\Component\Product\Model\ProductAttribute: + product_attribute_color: + code: 'color' + type: 'text' + storage_type: 'text' + position: 1 + translatable: 1 + +Sylius\Component\Product\Model\ProductAttributeValue: + product_attribute_value_color: + product: '@product_mug' + attribute: '@product_attribute_color' + localeCode: 'en_US' + value: 'red' + +Sylius\Component\Core\Model\Taxon: + mugs: + code: "mugs" + +Sylius\Component\Core\Model\ProductTaxon: + productTaxon1: + product: "@product_mug" + taxon: "@mugs" + position: 0 diff --git a/tests/PHPUnit/Integration/IntegrationTestCase.php b/tests/PHPUnit/Integration/IntegrationTestCase.php index 192808b1..d13f8b05 100644 --- a/tests/PHPUnit/Integration/IntegrationTestCase.php +++ b/tests/PHPUnit/Integration/IntegrationTestCase.php @@ -21,7 +21,8 @@ public function __construct( ) { parent::__construct($name, $data, $dataName); - $this->dataFixturesPath = __DIR__ . '/DataFixtures/ORM'; + $this->dataFixturesPath = __DIR__ . \DIRECTORY_SEPARATOR . 'DataFixtures' . \DIRECTORY_SEPARATOR . 'ORM'; + $this->expectedResponsesPath = __DIR__ . \DIRECTORY_SEPARATOR . 'Responses' . \DIRECTORY_SEPARATOR . 'Expected'; } protected function setUp(): void diff --git a/tests/PHPUnit/Integration/Responses/Expected/test_it_finds_products_by_name.json b/tests/PHPUnit/Integration/Responses/Expected/test_it_finds_products_by_name.json new file mode 100644 index 00000000..6e35a3c7 --- /dev/null +++ b/tests/PHPUnit/Integration/Responses/Expected/test_it_finds_products_by_name.json @@ -0,0 +1,47 @@ +{ + "items": [ + { + "productTaxons": [ + "/api/v2/shop/product-taxons/@string@" + ], + "mainTaxon": null, + "averageRating": 0, + "images": [], + "id": "@integer@", + "code": "MUG", + "variants": [], + "options": [], + "associations": [], + "createdAt": "@string@", + "updatedAt": "@string@", + "shortDescription": null, + "reviews": [], + "name": "Mug", + "description": "@string@", + "slug": "mug" + } + ], + "facets": { + "price": { + "buckets": [] + }, + "taxon": { + "doc_count_error_upper_bound": 0, + "sum_other_doc_count": 0, + "buckets": [ + { + "key": "mugs", + "doc_count": 1 + } + ] + } + }, + "pagination": { + "current_page": 1, + "has_previous_page": false, + "has_next_page": false, + "per_page": 9, + "total_items": 1, + "total_pages": 1 + } +} diff --git a/tests/PHPUnit/Integration/Responses/Expected/test_it_finds_products_by_name_and_facets.json b/tests/PHPUnit/Integration/Responses/Expected/test_it_finds_products_by_name_and_facets.json new file mode 100644 index 00000000..dcf7c6f6 --- /dev/null +++ b/tests/PHPUnit/Integration/Responses/Expected/test_it_finds_products_by_name_and_facets.json @@ -0,0 +1,57 @@ +{ + "items": [ + { + "productTaxons": [ + "/api/v2/shop/product-taxons/@string@" + ], + "mainTaxon": null, + "averageRating": 0, + "images": [], + "id": "@integer@", + "code": "MUG", + "variants": [], + "options": [], + "associations": [], + "createdAt": "@string@", + "updatedAt": "@string@", + "shortDescription": null, + "reviews": [], + "name": "Mug", + "description": "@string@", + "slug": "mug" + } + ], + "facets": { + "color": { + "doc_count_error_upper_bound": 0, + "sum_other_doc_count": 0, + "buckets": [ + { + "key": "red", + "doc_count": 1 + } + ] + }, + "price": { + "buckets": [] + }, + "taxon": { + "doc_count_error_upper_bound": 0, + "sum_other_doc_count": 0, + "buckets": [ + { + "key": "mugs", + "doc_count": 1 + } + ] + } + }, + "pagination": { + "current_page": 1, + "has_previous_page": false, + "has_next_page": false, + "per_page": 9, + "total_items": 1, + "total_pages": 1 + } +} From 396b423251ae11278b6925699edb28511eec7392 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gracjan=20J=C3=B3zefczyk?= Date: Thu, 6 Jun 2024 15:01:15 +0200 Subject: [PATCH 6/8] OP-303: Fix test paths --- .../ORM}/test_it_finds_products_by_name.yaml | 0 ..._it_finds_products_by_name_and_facets.yaml | 0 .../Integration/Api/ProductListingTest.php | 19 +++++++++++++++---- .../test_it_finds_products_by_name.json | 0 ..._it_finds_products_by_name_and_facets.json | 0 5 files changed, 15 insertions(+), 4 deletions(-) rename tests/PHPUnit/Integration/{DataFixtures/ORM/Api => Api/DataFixtures/ORM}/test_it_finds_products_by_name.yaml (100%) rename tests/PHPUnit/Integration/{DataFixtures/ORM/Api => Api/DataFixtures/ORM}/test_it_finds_products_by_name_and_facets.yaml (100%) rename tests/PHPUnit/Integration/{ => Api}/Responses/Expected/test_it_finds_products_by_name.json (100%) rename tests/PHPUnit/Integration/{ => Api}/Responses/Expected/test_it_finds_products_by_name_and_facets.json (100%) diff --git a/tests/PHPUnit/Integration/DataFixtures/ORM/Api/test_it_finds_products_by_name.yaml b/tests/PHPUnit/Integration/Api/DataFixtures/ORM/test_it_finds_products_by_name.yaml similarity index 100% rename from tests/PHPUnit/Integration/DataFixtures/ORM/Api/test_it_finds_products_by_name.yaml rename to tests/PHPUnit/Integration/Api/DataFixtures/ORM/test_it_finds_products_by_name.yaml diff --git a/tests/PHPUnit/Integration/DataFixtures/ORM/Api/test_it_finds_products_by_name_and_facets.yaml b/tests/PHPUnit/Integration/Api/DataFixtures/ORM/test_it_finds_products_by_name_and_facets.yaml similarity index 100% rename from tests/PHPUnit/Integration/DataFixtures/ORM/Api/test_it_finds_products_by_name_and_facets.yaml rename to tests/PHPUnit/Integration/Api/DataFixtures/ORM/test_it_finds_products_by_name_and_facets.yaml diff --git a/tests/PHPUnit/Integration/Api/ProductListingTest.php b/tests/PHPUnit/Integration/Api/ProductListingTest.php index 2752df13..9083d167 100644 --- a/tests/PHPUnit/Integration/Api/ProductListingTest.php +++ b/tests/PHPUnit/Integration/Api/ProductListingTest.php @@ -4,15 +4,26 @@ namespace PHPUnit\Integration\Api; +use ApiTestCase\JsonApiTestCase; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Process\Process; -use Tests\BitBag\SyliusElasticsearchPlugin\Integration\IntegrationTestCase; -final class ProductListingTest extends IntegrationTestCase +final class ProductListingTest extends JsonApiTestCase { + public function __construct( + ?string $name = null, + array $data = [], + string $dataName = '' + ) { + parent::__construct($name, $data, $dataName); + + $this->dataFixturesPath = __DIR__ . \DIRECTORY_SEPARATOR . 'DataFixtures' . \DIRECTORY_SEPARATOR . 'ORM'; + $this->expectedResponsesPath = __DIR__ . \DIRECTORY_SEPARATOR . 'Responses' . \DIRECTORY_SEPARATOR . 'Expected'; + } + public function test_it_finds_products_by_name(): void { - $this->loadFixturesFromFiles(['Api/test_it_finds_products_by_name.yaml']); + $this->loadFixturesFromFiles(['test_it_finds_products_by_name.yaml']); $this->populateElasticsearch(); $this->client->request('GET', '/api/v2/shop/products/search?query=mug'); @@ -22,7 +33,7 @@ public function test_it_finds_products_by_name(): void public function test_it_finds_products_by_name_and_facets(): void { - $this->loadFixturesFromFiles(['Api/test_it_finds_products_by_name_and_facets.yaml']); + $this->loadFixturesFromFiles(['test_it_finds_products_by_name_and_facets.yaml']); $this->populateElasticsearch(); $this->client->request('GET', '/api/v2/shop/products/search?query=mug&facets[color][]=red'); diff --git a/tests/PHPUnit/Integration/Responses/Expected/test_it_finds_products_by_name.json b/tests/PHPUnit/Integration/Api/Responses/Expected/test_it_finds_products_by_name.json similarity index 100% rename from tests/PHPUnit/Integration/Responses/Expected/test_it_finds_products_by_name.json rename to tests/PHPUnit/Integration/Api/Responses/Expected/test_it_finds_products_by_name.json diff --git a/tests/PHPUnit/Integration/Responses/Expected/test_it_finds_products_by_name_and_facets.json b/tests/PHPUnit/Integration/Api/Responses/Expected/test_it_finds_products_by_name_and_facets.json similarity index 100% rename from tests/PHPUnit/Integration/Responses/Expected/test_it_finds_products_by_name_and_facets.json rename to tests/PHPUnit/Integration/Api/Responses/Expected/test_it_finds_products_by_name_and_facets.json From 868e7d7d6410b887032cce1f73323bfa6d5484a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gracjan=20J=C3=B3zefczyk?= Date: Fri, 7 Jun 2024 07:21:21 +0200 Subject: [PATCH 7/8] OP-303: Add more tests --- ..._products_by_name_and_multiple_facets.yaml | 116 ++++++++++++++++++ .../Integration/Api/ProductListingTest.php | 26 +++- ..._products_by_name_and_multiple_facets.json | 85 +++++++++++++ 3 files changed, 225 insertions(+), 2 deletions(-) create mode 100644 tests/PHPUnit/Integration/Api/DataFixtures/ORM/test_it_finds_products_by_name_and_multiple_facets.yaml create mode 100644 tests/PHPUnit/Integration/Api/Responses/Expected/test_it_finds_products_by_name_and_multiple_facets.json diff --git a/tests/PHPUnit/Integration/Api/DataFixtures/ORM/test_it_finds_products_by_name_and_multiple_facets.yaml b/tests/PHPUnit/Integration/Api/DataFixtures/ORM/test_it_finds_products_by_name_and_multiple_facets.yaml new file mode 100644 index 00000000..4473d549 --- /dev/null +++ b/tests/PHPUnit/Integration/Api/DataFixtures/ORM/test_it_finds_products_by_name_and_multiple_facets.yaml @@ -0,0 +1,116 @@ +Sylius\Component\Core\Model\Channel: + channel_web: + code: 'WEB' + name: 'Web Channel' + hostname: 'localhost' + description: 'Lorem ipsum' + baseCurrency: '@currency_usd' + defaultLocale: '@locale_en' + locales: ['@locale_en'] + color: 'black' + enabled: true + taxCalculationStrategy: 'order_items_based' + +Sylius\Component\Currency\Model\Currency: + currency_usd: + code: 'USD' + +Sylius\Component\Locale\Model\Locale: + locale_en: + code: 'en_US' + +Sylius\Component\Core\Model\Product: + product_mug: + code: 'MUG' + channels: ['@channel_web'] + currentLocale: 'en_US' + translations: + en_US: '@product_translation_mug' + product_mug2: + code: 'MUG2' + channels: ['@channel_web'] + currentLocale: 'en_US' + translations: + en_US: '@product_translation_mug2' + product_mug3: + code: 'MUG3' + channels: ['@channel_web'] + currentLocale: 'en_US' + translations: + en_US: '@product_translation_mug3' + +Sylius\Component\Core\Model\ProductTranslation: + product_translation_mug: + slug: 'mug' + locale: 'en_US' + name: 'Mug' + description: '' + translatable: '@product_mug' + product_translation_mug2: + slug: 'mug-2' + locale: 'en_US' + name: 'Mug 2' + description: '' + translatable: '@product_mug2' + product_translation_mug3: + slug: 'mug-3' + locale: 'en_US' + name: 'Mug 3' + description: '' + translatable: '@product_mug3' + +Sylius\Component\Product\Model\ProductAttributeTranslation: + attributeTranslation1: + locale: en_US + name: "Product color" + translatable: "@product_attribute_color" + attributeTranslation2: + locale: en_US + name: "Product material" + translatable: "@product_attribute_material" + +Sylius\Component\Product\Model\ProductAttribute: + product_attribute_color: + code: 'color' + type: 'text' + storage_type: 'text' + position: 1 + translatable: 1 + product_attribute_material: + code: 'material' + type: 'text' + storage_type: 'text' + position: 1 + translatable: 1 + +Sylius\Component\Product\Model\ProductAttributeValue: + product_attribute_value_color_1: + product: '@product_mug' + attribute: '@product_attribute_color' + localeCode: 'en_US' + value: 'red' + product_attribute_value_color_2: + product: '@product_mug2' + attribute: '@product_attribute_color' + localeCode: 'en_US' + value: 'red' + product_attribute_value_material_1: + product: '@product_mug' + attribute: '@product_attribute_material' + localeCode: 'en_US' + value: 'ceramic' + product_attribute_value_material_2: + product: '@product_mug2' + attribute: '@product_attribute_material' + localeCode: 'en_US' + value: 'ceramic' + +Sylius\Component\Core\Model\Taxon: + mugs: + code: "mugs" + +Sylius\Component\Core\Model\ProductTaxon: + productTaxon1: + product: "@product_mug" + taxon: "@mugs" + position: 0 diff --git a/tests/PHPUnit/Integration/Api/ProductListingTest.php b/tests/PHPUnit/Integration/Api/ProductListingTest.php index 9083d167..3f3654ec 100644 --- a/tests/PHPUnit/Integration/Api/ProductListingTest.php +++ b/tests/PHPUnit/Integration/Api/ProductListingTest.php @@ -26,7 +26,11 @@ public function test_it_finds_products_by_name(): void $this->loadFixturesFromFiles(['test_it_finds_products_by_name.yaml']); $this->populateElasticsearch(); - $this->client->request('GET', '/api/v2/shop/products/search?query=mug'); + $this->client->request( + 'GET', + '/api/v2/shop/products/search?query=mug' + ); + $response = $this->client->getResponse(); $this->assertResponse($response, 'test_it_finds_products_by_name', Response::HTTP_OK); } @@ -36,11 +40,29 @@ public function test_it_finds_products_by_name_and_facets(): void $this->loadFixturesFromFiles(['test_it_finds_products_by_name_and_facets.yaml']); $this->populateElasticsearch(); - $this->client->request('GET', '/api/v2/shop/products/search?query=mug&facets[color][]=red'); + $this->client->request( + 'GET', + '/api/v2/shop/products/search?query=mug&facets[color][]=red' + ); + $response = $this->client->getResponse(); $this->assertResponse($response, 'test_it_finds_products_by_name_and_facets', Response::HTTP_OK); } + public function test_it_finds_products_by_name_and_multiple_facets(): void + { + $this->loadFixturesFromFiles(['test_it_finds_products_by_name_and_multiple_facets.yaml']); + $this->populateElasticsearch(); + + $this->client->request( + 'GET', + '/api/v2/shop/products/search?query=mug&facets[color][]=red&facets[material][]=ceramic' + ); + + $response = $this->client->getResponse(); + $this->assertResponse($response, 'test_it_finds_products_by_name_and_multiple_facets', Response::HTTP_OK); + } + private function populateElasticsearch(): void { $process = new Process(['tests/Application/bin/console', 'fos:elastica:populate']); diff --git a/tests/PHPUnit/Integration/Api/Responses/Expected/test_it_finds_products_by_name_and_multiple_facets.json b/tests/PHPUnit/Integration/Api/Responses/Expected/test_it_finds_products_by_name_and_multiple_facets.json new file mode 100644 index 00000000..6cf156a0 --- /dev/null +++ b/tests/PHPUnit/Integration/Api/Responses/Expected/test_it_finds_products_by_name_and_multiple_facets.json @@ -0,0 +1,85 @@ +{ + "items": [ + { + "productTaxons": [ + "/api/v2/shop/product-taxons/@string@" + ], + "mainTaxon": null, + "averageRating": 0, + "images": [], + "id": "@integer@", + "code": "MUG", + "variants": [], + "options": [], + "associations": [], + "createdAt": "@string@", + "updatedAt": "@string@", + "shortDescription": null, + "reviews": [], + "name": "Mug", + "description": "@string@", + "slug": "mug" + }, + { + "productTaxons": [], + "mainTaxon": null, + "averageRating": 0, + "images": [], + "id": "@integer@", + "code": "MUG2", + "variants": [], + "options": [], + "associations": [], + "createdAt": "@string@", + "updatedAt": "@string@", + "shortDescription": null, + "reviews": [], + "name": "Mug 2", + "description": "@string@", + "slug": "mug-2" + } + ], + "facets": { + "material": { + "doc_count_error_upper_bound": 0, + "sum_other_doc_count": 0, + "buckets": [ + { + "key": "ceramic", + "doc_count": 2 + } + ] + }, + "color": { + "doc_count_error_upper_bound": 0, + "sum_other_doc_count": 0, + "buckets": [ + { + "key": "red", + "doc_count": 2 + } + ] + }, + "price": { + "buckets": [] + }, + "taxon": { + "doc_count_error_upper_bound": 0, + "sum_other_doc_count": 0, + "buckets": [ + { + "key": "mugs", + "doc_count": 1 + } + ] + } + }, + "pagination": { + "current_page": 1, + "has_previous_page": false, + "has_next_page": false, + "per_page": 9, + "total_items": 2, + "total_pages": 1 + } +} From f9f9fd5c56156b13ba465bdfde12fa99f2e3d54d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gracjan=20J=C3=B3zefczyk?= Date: Fri, 7 Jun 2024 10:40:06 +0200 Subject: [PATCH 8/8] OP-303: Add OpenSource headers --- src/Api/DataProvider/ProductCollectionDataProvider.php | 8 ++++++++ src/Api/RequestDataHandler/RequestDataHandler.php | 8 ++++++++ .../RequestDataHandler/RequestDataHandlerInterface.php | 8 ++++++++ src/Api/Resolver/FacetsResolver.php | 8 ++++++++ src/Api/Resolver/FacetsResolverInterface.php | 8 ++++++++ tests/PHPUnit/Integration/Api/ProductListingTest.php | 8 ++++++++ 6 files changed, 48 insertions(+) diff --git a/src/Api/DataProvider/ProductCollectionDataProvider.php b/src/Api/DataProvider/ProductCollectionDataProvider.php index 4e2afc8d..7228ab42 100644 --- a/src/Api/DataProvider/ProductCollectionDataProvider.php +++ b/src/Api/DataProvider/ProductCollectionDataProvider.php @@ -1,5 +1,13 @@