diff --git a/doc/swagger.yml b/doc/swagger.yml
index 726ae85e1..7ee6a5cc3 100644
--- a/doc/swagger.yml
+++ b/doc/swagger.yml
@@ -553,6 +553,35 @@ paths:
schema:
$ref: "#/definitions/ProductDetails"
+ /products/by-phrase/{phrase}:
+ get:
+ tags:
+ - "products"
+ summary: "Show a product catalog."
+ description: "This endpoint will return a paginated list of products for given phrase."
+ operationId: "productCatalogByPhrase"
+ parameters:
+ - name: "phrase"
+ in: "path"
+ description: "Phrase to search for."
+ required: true
+ type: "string"
+ - name: "locale"
+ in: "query"
+ description: "Locale in which products should be shown."
+ required: false
+ type: "string"
+ - name: "includeDescription"
+ in: "query"
+ description: "Should the description included in search."
+ required: false
+ type: "boolean"
+ responses:
+ 200:
+ description: "Show a product with the given code."
+ schema:
+ $ref: "#/definitions/ProductDetails"
+
/products/by-slug/{slug}/reviews:
parameters:
- name: "slug"
diff --git a/src/Controller/Product/ShowProductCatalogByPhraseAction.php b/src/Controller/Product/ShowProductCatalogByPhraseAction.php
new file mode 100644
index 000000000..ff899705a
--- /dev/null
+++ b/src/Controller/Product/ShowProductCatalogByPhraseAction.php
@@ -0,0 +1,59 @@
+viewHandler = $viewHandler;
+ $this->productCatalogViewRepository = $productLatestQuery;
+ $this->channelContext = $channelContext;
+ }
+
+ public function __invoke(Request $request): Response
+ {
+ try {
+ $channel = $this->channelContext->getChannel();
+ $phrase = $request->attributes->get('phrase');
+ $queryParameters = $request->query->all();
+ $queryParameters['phrase'] = $phrase;
+
+ return $this->viewHandler->handle(View::create($this->productCatalogViewRepository->findByPhrase(
+ $phrase,
+ $channel->getCode(),
+ new PaginatorDetails($request->attributes->get('_route'), $queryParameters),
+ $request->query->getBoolean('includeDescription', false),
+ $request->query->get('locale')
+ ), Response::HTTP_OK));
+ } catch (ChannelNotFoundException $exception) {
+ throw new NotFoundHttpException('Channel has not been found.');
+ } catch (\InvalidArgumentException $exception) {
+ throw new NotFoundHttpException($exception->getMessage());
+ }
+ }
+}
diff --git a/src/Resources/config/routing.yml b/src/Resources/config/routing.yml
index 014cef2aa..206b3afce 100644
--- a/src/Resources/config/routing.yml
+++ b/src/Resources/config/routing.yml
@@ -10,6 +10,10 @@ sylius_shop_api_product_by_code:
resource: "@SyliusShopApiPlugin/Resources/config/routing/productByCode.yml"
prefix: /shop-api
+sylius_shop_api_product_by_phrase:
+ resource: "@SyliusShopApiPlugin/Resources/config/routing/productByPhrase.yml"
+ prefix: /shop-api
+
sylius_shop_api_taxon:
resource: "@SyliusShopApiPlugin/Resources/config/routing/taxon.yml"
prefix: /shop-api
diff --git a/src/Resources/config/routing/productByPhrase.yml b/src/Resources/config/routing/productByPhrase.yml
new file mode 100644
index 000000000..b75f32043
--- /dev/null
+++ b/src/Resources/config/routing/productByPhrase.yml
@@ -0,0 +1,7 @@
+sylius_shop_api_product_show_by_phrase:
+ path: /products/by-phrase/{phrase}
+ methods: [GET]
+ defaults:
+ _controller: sylius.shop_api_plugin.controller.product.show_product_catalog_by_phrase_action
+ requirements:
+ phrase: .+
diff --git a/src/Resources/config/services/actions/product.xml b/src/Resources/config/services/actions/product.xml
index 058952730..dacc5bbe4 100644
--- a/src/Resources/config/services/actions/product.xml
+++ b/src/Resources/config/services/actions/product.xml
@@ -36,6 +36,14 @@
+
+
+
+
+
+
diff --git a/src/ViewRepository/Product/ProductCatalogViewRepository.php b/src/ViewRepository/Product/ProductCatalogViewRepository.php
index 00af80ab9..6bfd6d14c 100644
--- a/src/ViewRepository/Product/ProductCatalogViewRepository.php
+++ b/src/ViewRepository/Product/ProductCatalogViewRepository.php
@@ -4,6 +4,7 @@
namespace Sylius\ShopApiPlugin\ViewRepository\Product;
+use Doctrine\ORM\QueryBuilder;
use Pagerfanta\Adapter\DoctrineORMAdapter;
use Pagerfanta\Pagerfanta;
use Sylius\Component\Channel\Repository\ChannelRepositoryInterface;
@@ -82,6 +83,22 @@ public function findByTaxonCode(string $taxonCode, string $channelCode, Paginato
return $this->findByTaxon($taxon, $channel, $paginatorDetails, $localeCode);
}
+ public function findByPhrase(string $phrase, string $channelCode, PaginatorDetails $paginatorDetails, ?bool $includeDescription, ?string $localeCode): PageView
+ {
+ $channel = $this->getChannel($channelCode);
+ $localeCode = $this->supportedLocaleProvider->provide($localeCode, $channel);
+
+ $queryBuilder = $this->productRepository->createListQueryBuilder($localeCode);
+ $queryBuilder->andWhere('translation.name LIKE :phrase');
+ if (true === $includeDescription) {
+ $queryBuilder->orWhere('translation.description LIKE :phrase');
+ $queryBuilder->orWhere('translation.shortDescription LIKE :phrase');
+ }
+ $queryBuilder->setParameter('phrase', '%' . $phrase . '%');
+
+ return $this->createPageView($queryBuilder, $paginatorDetails, $channel, $localeCode);
+ }
+
private function getChannel(string $channelCode): ChannelInterface
{
/** @var ChannelInterface $channel */
@@ -98,6 +115,11 @@ private function findByTaxon(TaxonInterface $taxon, ChannelInterface $channel, P
$queryBuilder->addSelect('productTaxon');
$queryBuilder->addOrderBy('productTaxon.position');
+ return $this->createPageView($queryBuilder, $paginatorDetails, $channel, $localeCode);
+ }
+
+ private function createPageView(QueryBuilder $queryBuilder, PaginatorDetails $paginatorDetails, ChannelInterface $channel, string $localeCode): PageView
+ {
$pagerfanta = new Pagerfanta(new DoctrineORMAdapter($queryBuilder));
$pagerfanta->setMaxPerPage($paginatorDetails->limit());
diff --git a/src/ViewRepository/Product/ProductCatalogViewRepositoryInterface.php b/src/ViewRepository/Product/ProductCatalogViewRepositoryInterface.php
index e2e174bdf..1add9876b 100644
--- a/src/ViewRepository/Product/ProductCatalogViewRepositoryInterface.php
+++ b/src/ViewRepository/Product/ProductCatalogViewRepositoryInterface.php
@@ -12,4 +12,6 @@ interface ProductCatalogViewRepositoryInterface
public function findByTaxonSlug(string $taxonSlug, string $channelCode, PaginatorDetails $paginatorDetails, ?string $localeCode): PageView;
public function findByTaxonCode(string $taxonCode, string $channelCode, PaginatorDetails $paginatorDetails, ?string $localeCode): PageView;
+
+ public function findByPhrase(string $phrase, string $channelCode, PaginatorDetails $paginatorDetails, ?bool $includeDescription, ?string $localeCode): PageView;
}
diff --git a/tests/Controller/Product/ShowCatalogByPhraseApiTest.php b/tests/Controller/Product/ShowCatalogByPhraseApiTest.php
new file mode 100644
index 000000000..72fc34f46
--- /dev/null
+++ b/tests/Controller/Product/ShowCatalogByPhraseApiTest.php
@@ -0,0 +1,100 @@
+loadFixturesFromFiles(['shop.yml']);
+
+ $this->client->request('GET', '/shop-api/products/by-phrase/mug', [], [], self::CONTENT_TYPE_HEADER);
+ $response = $this->client->getResponse();
+
+ $this->assertResponse($response, 'product/product_list_page_by_phrase_mug_response', Response::HTTP_OK);
+ }
+
+ /**
+ * @test
+ */
+ public function it_shows_empty_products_list_for_non_existing_products(): void
+ {
+ $this->loadFixturesFromFiles(['shop.yml']);
+
+ $this->client->request('GET', '/shop-api/products/by-phrase/unknown', [], [], self::CONTENT_TYPE_HEADER);
+ $response = $this->client->getResponse();
+
+ $this->assertResponse($response, 'product/product_list_page_by_phrase_empty_response', Response::HTTP_OK);
+ }
+
+ /**
+ * @test
+ */
+ public function it_shows_paginated_products_for_phrase_including_description(): void
+ {
+ $this->loadFixturesFromFiles(['shop.yml']);
+
+ $this->client->request('GET', '/shop-api/products/by-phrase/Lorem', ['includeDescription' => true], [], self::CONTENT_TYPE_HEADER);
+ $response = $this->client->getResponse();
+
+ $this->assertResponse($response, 'product/product_list_page_by_phrase_mug_including_description_response', Response::HTTP_OK);
+ }
+
+ /**
+ * @test
+ */
+ public function it_shows_paginated_products_for_phrase_including_short_description(): void
+ {
+ $this->loadFixturesFromFiles(['shop.yml']);
+
+ $this->client->request('GET', '/shop-api/products/by-phrase/short', ['includeDescription' => true], [], self::CONTENT_TYPE_HEADER);
+ $response = $this->client->getResponse();
+
+ $this->assertResponse($response, 'product/product_list_page_by_phrase_mug_including_short_description_response', Response::HTTP_OK);
+ }
+
+ /**
+ * @test
+ */
+ public function it_shows_paginated_products_for_phrase_in_different_language(): void
+ {
+ $this->loadFixturesFromFiles(['shop.yml']);
+
+ $this->client->request('GET', '/shop-api/products/by-phrase/becher?locale=de_DE', [], [], self::CONTENT_TYPE_HEADER);
+ $response = $this->client->getResponse();
+
+ $this->assertResponse($response, 'product/product_list_page_by_phrase_mug_in_german_response', Response::HTTP_OK);
+ }
+
+ /**
+ * @test
+ */
+ public function it_shows_paginated_products_for_phrase_in_different_language_including_description(): void
+ {
+ $this->loadFixturesFromFiles(['shop.yml']);
+
+ $this->client->request('GET', '/shop-api/products/by-phrase/Beschreibung?locale=de_DE', ['includeDescription' => true], [], self::CONTENT_TYPE_HEADER);
+ $response = $this->client->getResponse();
+
+ $this->assertResponse($response, 'product/product_list_page_by_phrase_mug_in_german_including_description_response', Response::HTTP_OK);
+ }
+
+ /**
+ * @test
+ */
+ public function it_throws_a_not_found_exception_if_channel_has_not_been_found(): void
+ {
+ $this->client->request('GET', '/shop-api/products/by-phrase/mug', [], [], self::CONTENT_TYPE_HEADER);
+ $response = $this->client->getResponse();
+
+ $this->assertResponse($response, 'product/channel_has_not_been_found_response', Response::HTTP_NOT_FOUND);
+ }
+}
diff --git a/tests/DataFixtures/ORM/shop.yml b/tests/DataFixtures/ORM/shop.yml
index 4e3780a72..602e75c06 100644
--- a/tests/DataFixtures/ORM/shop.yml
+++ b/tests/DataFixtures/ORM/shop.yml
@@ -109,6 +109,7 @@ Sylius\Component\Core\Model\ProductTranslation:
locale: "en_GB"
name: "Logan Shoes"
description: "Some description Lorem ipsum dolor sit amet."
+ shortDescription: "Short description Lorem ipsum dolor sit amet."
translatable: "@shoes"
Sylius\Component\Core\Model\ProductVariant:
diff --git a/tests/Responses/Expected/product/product_list_latest_4_response.json b/tests/Responses/Expected/product/product_list_latest_4_response.json
index 37ce0dd69..7f75f1939 100644
--- a/tests/Responses/Expected/product/product_list_latest_4_response.json
+++ b/tests/Responses/Expected/product/product_list_latest_4_response.json
@@ -293,6 +293,7 @@
"slug": "logan-shoes",
"channelCode": "WEB_GB",
"description": "Some description Lorem ipsum dolor sit amet.",
+ "shortDescription": "Short description Lorem ipsum dolor sit amet.",
"averageRating": 0,
"taxons": {
"others": []
diff --git a/tests/Responses/Expected/product/product_list_page_by_phrase_empty_response.json b/tests/Responses/Expected/product/product_list_page_by_phrase_empty_response.json
new file mode 100644
index 000000000..3ca74d9e4
--- /dev/null
+++ b/tests/Responses/Expected/product/product_list_page_by_phrase_empty_response.json
@@ -0,0 +1,13 @@
+{
+ "page": 1,
+ "limit": 10,
+ "pages": 1,
+ "total": 0,
+ "_links": {
+ "self": "/shop-api/products/by-phrase/unknown?page=1&limit=10",
+ "first": "/shop-api/products/by-phrase/unknown?page=1&limit=10",
+ "last": "/shop-api/products/by-phrase/unknown?page=1&limit=10",
+ "next": "/shop-api/products/by-phrase/unknown?page=1&limit=10"
+ },
+ "items": []
+}
diff --git a/tests/Responses/Expected/product/product_list_page_by_phrase_mug_in_german_including_description_response.json b/tests/Responses/Expected/product/product_list_page_by_phrase_mug_in_german_including_description_response.json
new file mode 100644
index 000000000..1fa083e78
--- /dev/null
+++ b/tests/Responses/Expected/product/product_list_page_by_phrase_mug_in_german_including_description_response.json
@@ -0,0 +1,242 @@
+{
+ "page": 1,
+ "limit": 10,
+ "pages": 1,
+ "total": 1,
+ "_links": {
+ "self": "\/shop-api\/products\/by-phrase\/Beschreibung?locale=de_DE&includeDescription=1&page=1&limit=10",
+ "first": "\/shop-api\/products\/by-phrase\/Beschreibung?locale=de_DE&includeDescription=1&page=1&limit=10",
+ "last": "\/shop-api\/products\/by-phrase\/Beschreibung?locale=de_DE&includeDescription=1&page=1&limit=10",
+ "next": "\/shop-api\/products\/by-phrase\/Beschreibung?locale=de_DE&includeDescription=1&page=1&limit=10"
+ },
+ "items": [
+ {
+ "code": "LOGAN_HAT_CODE",
+ "name": "Logan Hut",
+ "slug": "logan-hut",
+ "channelCode": "WEB_GB",
+ "description": "Einige Beschreibung Lorem ipsum dolor sit amet.",
+ "averageRating": 0,
+ "taxons": {
+ "main": "HAT",
+ "others": [
+ "HAT",
+ "BRAND"
+ ]
+ },
+ "variants": {
+ "SMALL_RED_LOGAN_HAT_CODE": {
+ "code": "SMALL_RED_LOGAN_HAT_CODE",
+ "name": "Klein Rot Logan Hut",
+ "axis": [
+ "HAT_SIZE_S",
+ "HAT_COLOR_RED"
+ ],
+ "nameAxis": {
+ "HAT_SIZE_S": "Size S",
+ "HAT_COLOR_RED": "Farbe Rot"
+ },
+ "price": {
+ "current": 500,
+ "currency": "GBP"
+ },
+ "images": []
+ },
+ "LARGE_RED_LOGAN_HAT_CODE": {
+ "code": "LARGE_RED_LOGAN_HAT_CODE",
+ "name": "Large Red Logan Hat",
+ "axis": [
+ "HAT_SIZE_L",
+ "HAT_COLOR_RED"
+ ],
+ "nameAxis": {
+ "HAT_SIZE_L": "Size L",
+ "HAT_COLOR_RED": "Farbe Rot"
+ },
+ "price": {
+ "current": 999,
+ "currency": "GBP"
+ },
+ "images": []
+ },
+ "SMALL_BLUE_LOGAN_HAT_CODE": {
+ "code": "SMALL_BLUE_LOGAN_HAT_CODE",
+ "name": "Klein Blau Logan Hut",
+ "axis": [
+ "HAT_SIZE_S",
+ "HAT_COLOR_BLUE"
+ ],
+ "nameAxis": {
+ "HAT_SIZE_S": "Size S",
+ "HAT_COLOR_BLUE": "Farbe Blau"
+ },
+ "price": {
+ "current": 1500,
+ "currency": "GBP"
+ },
+ "images": []
+ },
+ "LARGE_BLUE_LOGAN_HAT_CODE": {
+ "code": "LARGE_BLUE_LOGAN_HAT_CODE",
+ "name": "Gro\u00dfes Blau Logan Hut",
+ "axis": [
+ "HAT_SIZE_L",
+ "HAT_COLOR_BLUE"
+ ],
+ "nameAxis": {
+ "HAT_SIZE_L": "Size L",
+ "HAT_COLOR_BLUE": "Farbe Blau"
+ },
+ "price": {
+ "current": 2599,
+ "currency": "GBP"
+ },
+ "images": []
+ }
+ },
+ "attributes": [],
+ "associations": {
+ "CROSS_SELL_ASSOCIATION_TYPE": [
+ {
+ "code": "LOGAN_MUG_CODE",
+ "name": "Logan Becher",
+ "slug": "logan-becher",
+ "channelCode": "WEB_GB",
+ "averageRating": 0,
+ "taxons": {
+ "main": "MUG",
+ "others": [
+ "MUG",
+ "BRAND"
+ ]
+ },
+ "variants": {
+ "LOGAN_MUG_CODE": {
+ "code": "LOGAN_MUG_CODE",
+ "name": "Logan Becher",
+ "axis": [],
+ "nameAxis": {},
+ "price": {
+ "current": 1999,
+ "currency": "GBP"
+ },
+ "originalPrice": {
+ "current": 2999,
+ "currency": "GBP"
+ },
+ "images": [
+ {
+ "code": "thumbnail",
+ "path": "\/pants.jpeg",
+ "cachedPath": "http:\/\/localhost\/media\/cache\/sylius_shop_api\/pants.jpeg"
+ }
+ ]
+ }
+ },
+ "attributes": [
+ {
+ "code": "MUG_MATERIAL_CODE",
+ "name": "Becher Material",
+ "value": "Wood"
+ }
+ ],
+ "associations": [],
+ "images": [
+ {
+ "code": "thumbnail",
+ "path": "\/pants.jpeg",
+ "cachedPath": "http:\/\/localhost\/media\/cache\/sylius_shop_api\/pants.jpeg"
+ }
+ ],
+ "_links": {
+ "self": {
+ "href": "\/shop-api\/products\/by-slug\/logan-becher"
+ }
+ }
+ },
+ {
+ "code": "LOGAN_T_SHIRT_CODE",
+ "name": "Logan T-Shirt",
+ "slug": "logan-t-shirt",
+ "channelCode": "WEB_GB",
+ "description": "Some description Lorem ipsum dolor sit amet.",
+ "averageRating": 0,
+ "taxons": {
+ "main": "T_SHIRTS",
+ "others": [
+ "WOMEN_T_SHIRTS",
+ "BRAND"
+ ]
+ },
+ "variants": {
+ "SMALL_LOGAN_T_SHIRT_CODE": {
+ "code": "SMALL_LOGAN_T_SHIRT_CODE",
+ "name": "Small Logan T-Shirt",
+ "axis": [],
+ "nameAxis": {},
+ "price": {
+ "current": 1999,
+ "currency": "GBP"
+ },
+ "images": [
+ {
+ "code": "thumbnail",
+ "path": "\/pants.jpeg",
+ "cachedPath": "http:\/\/localhost\/media\/cache\/sylius_shop_api\/pants.jpeg"
+ }
+ ]
+ },
+ "LARGE_LOGAN_T_SHIRT_CODE": {
+ "code": "LARGE_LOGAN_T_SHIRT_CODE",
+ "name": "Large Logan T-Shirt",
+ "axis": [],
+ "nameAxis": {},
+ "price": {
+ "current": 2999,
+ "currency": "GBP"
+ },
+ "images": [
+ {
+ "code": "thumbnail",
+ "path": "\/pants.jpeg",
+ "cachedPath": "http:\/\/localhost\/media\/cache\/sylius_shop_api\/pants.jpeg"
+ }
+ ]
+ }
+ },
+ "attributes": [],
+ "associations": [],
+ "images": [
+ {
+ "code": "thumbnail",
+ "path": "\/pants.jpeg",
+ "cachedPath": "http:\/\/localhost\/media\/cache\/sylius_shop_api\/pants.jpeg"
+ },
+ {
+ "code": "thumbnail",
+ "path": "\/pants.jpeg",
+ "cachedPath": "http:\/\/localhost\/media\/cache\/sylius_shop_api\/pants.jpeg"
+ },
+ {
+ "code": "thumbnail",
+ "path": "\/pants.jpeg",
+ "cachedPath": "http:\/\/localhost\/media\/cache\/sylius_shop_api\/pants.jpeg"
+ }
+ ],
+ "_links": {
+ "self": {
+ "href": "\/shop-api\/products\/by-slug\/logan-t-shirt"
+ }
+ }
+ }
+ ]
+ },
+ "images": [],
+ "_links": {
+ "self": {
+ "href": "\/shop-api\/products\/by-slug\/logan-hut"
+ }
+ }
+ }
+ ]
+}
diff --git a/tests/Responses/Expected/product/product_list_page_by_phrase_mug_in_german_response.json b/tests/Responses/Expected/product/product_list_page_by_phrase_mug_in_german_response.json
new file mode 100644
index 000000000..f325d92bd
--- /dev/null
+++ b/tests/Responses/Expected/product/product_list_page_by_phrase_mug_in_german_response.json
@@ -0,0 +1,71 @@
+{
+ "page": 1,
+ "limit": 10,
+ "pages": 1,
+ "total": 1,
+ "_links": {
+ "self": "\/shop-api\/products\/by-phrase\/becher?locale=de_DE&page=1&limit=10",
+ "first": "\/shop-api\/products\/by-phrase\/becher?locale=de_DE&page=1&limit=10",
+ "last": "\/shop-api\/products\/by-phrase\/becher?locale=de_DE&page=1&limit=10",
+ "next": "\/shop-api\/products\/by-phrase\/becher?locale=de_DE&page=1&limit=10"
+ },
+ "items": [
+ {
+ "code": "LOGAN_MUG_CODE",
+ "name": "Logan Becher",
+ "slug": "logan-becher",
+ "channelCode": "WEB_GB",
+ "averageRating": 0,
+ "taxons": {
+ "main": "MUG",
+ "others": [
+ "MUG",
+ "BRAND"
+ ]
+ },
+ "variants": {
+ "LOGAN_MUG_CODE": {
+ "code": "LOGAN_MUG_CODE",
+ "name": "Logan Becher",
+ "axis": [],
+ "nameAxis": {},
+ "price": {
+ "current": 1999,
+ "currency": "GBP"
+ },
+ "originalPrice": {
+ "current": 2999,
+ "currency": "GBP"
+ },
+ "images": [
+ {
+ "code": "thumbnail",
+ "path": "\/pants.jpeg",
+ "cachedPath": "http:\/\/localhost\/media\/cache\/sylius_shop_api\/pants.jpeg"
+ }
+ ]
+ }
+ },
+ "attributes": [
+ {
+ "code": "MUG_MATERIAL_CODE",
+ "name": "Becher Material",
+ "value": "Wood"
+ }
+ ],
+ "associations": [],
+ "images": [
+ {
+ "code": "thumbnail",
+ "path": "\/pants.jpeg",
+ "cachedPath": "http:\/\/localhost\/media\/cache\/sylius_shop_api\/pants.jpeg"
+ }
+ ],
+ "_links": {
+ "self": {
+ "href": "\/shop-api\/products\/by-slug\/logan-becher"
+ }
+ }
+ }
+ ]
+}
diff --git a/tests/Responses/Expected/product/product_list_page_by_phrase_mug_including_description_response.json b/tests/Responses/Expected/product/product_list_page_by_phrase_mug_including_description_response.json
new file mode 100644
index 000000000..b9179f29a
--- /dev/null
+++ b/tests/Responses/Expected/product/product_list_page_by_phrase_mug_including_description_response.json
@@ -0,0 +1,397 @@
+{
+ "page": 1,
+ "limit": 10,
+ "pages": 1,
+ "total": 4,
+ "_links": {
+ "self": "\/shop-api\/products\/by-phrase\/Lorem?includeDescription=1&page=1&limit=10",
+ "first": "\/shop-api\/products\/by-phrase\/Lorem?includeDescription=1&page=1&limit=10",
+ "last": "\/shop-api\/products\/by-phrase\/Lorem?includeDescription=1&page=1&limit=10",
+ "next": "\/shop-api\/products\/by-phrase\/Lorem?includeDescription=1&page=1&limit=10"
+ },
+ "items": [
+ {
+ "code": "LOGAN_MUG_CODE",
+ "name": "Logan Mug",
+ "slug": "logan-mug",
+ "channelCode": "WEB_GB",
+ "description": "Some description Lorem ipsum dolor sit amet.",
+ "averageRating": 0,
+ "taxons": {
+ "main": "MUG",
+ "others": [
+ "MUG",
+ "BRAND"
+ ]
+ },
+ "variants": {
+ "LOGAN_MUG_CODE": {
+ "code": "LOGAN_MUG_CODE",
+ "name": "Logan Mug",
+ "axis": [],
+ "nameAxis": {},
+ "price": {
+ "current": 1999,
+ "currency": "GBP"
+ },
+ "originalPrice": {
+ "current": 2999,
+ "currency": "GBP"
+ },
+ "images": [
+ {
+ "code": "thumbnail",
+ "path": "\/pants.jpeg",
+ "cachedPath": "http:\/\/localhost\/media\/cache\/sylius_shop_api\/pants.jpeg"
+ }
+ ]
+ }
+ },
+ "attributes": [
+ {
+ "code": "MUG_MATERIAL_CODE",
+ "name": "Mug material",
+ "value": "Wood"
+ }
+ ],
+ "associations": [],
+ "images": [
+ {
+ "code": "thumbnail",
+ "path": "\/pants.jpeg",
+ "cachedPath": "http:\/\/localhost\/media\/cache\/sylius_shop_api\/pants.jpeg"
+ }
+ ],
+ "_links": {
+ "self": {
+ "href": "\/shop-api\/products\/by-slug\/logan-mug"
+ }
+ }
+ },
+ {
+ "code": "LOGAN_T_SHIRT_CODE",
+ "name": "Logan T-Shirt",
+ "slug": "logan-t-shirt",
+ "channelCode": "WEB_GB",
+ "description": "Some description Lorem ipsum dolor sit amet.",
+ "averageRating": 0,
+ "taxons": {
+ "main": "T_SHIRTS",
+ "others": [
+ "WOMEN_T_SHIRTS",
+ "BRAND"
+ ]
+ },
+ "variants": {
+ "SMALL_LOGAN_T_SHIRT_CODE": {
+ "code": "SMALL_LOGAN_T_SHIRT_CODE",
+ "name": "Small Logan T-Shirt",
+ "axis": [],
+ "nameAxis": {},
+ "price": {
+ "current": 1999,
+ "currency": "GBP"
+ },
+ "images": [
+ {
+ "code": "thumbnail",
+ "path": "\/pants.jpeg",
+ "cachedPath": "http:\/\/localhost\/media\/cache\/sylius_shop_api\/pants.jpeg"
+ }
+ ]
+ },
+ "LARGE_LOGAN_T_SHIRT_CODE": {
+ "code": "LARGE_LOGAN_T_SHIRT_CODE",
+ "name": "Large Logan T-Shirt",
+ "axis": [],
+ "nameAxis": {},
+ "price": {
+ "current": 2999,
+ "currency": "GBP"
+ },
+ "images": [
+ {
+ "code": "thumbnail",
+ "path": "\/pants.jpeg",
+ "cachedPath": "http:\/\/localhost\/media\/cache\/sylius_shop_api\/pants.jpeg"
+ }
+ ]
+ }
+ },
+ "attributes": [],
+ "associations": [],
+ "images": [
+ {
+ "code": "thumbnail",
+ "path": "\/pants.jpeg",
+ "cachedPath": "http:\/\/localhost\/media\/cache\/sylius_shop_api\/pants.jpeg"
+ },
+ {
+ "code": "thumbnail",
+ "path": "\/pants.jpeg",
+ "cachedPath": "http:\/\/localhost\/media\/cache\/sylius_shop_api\/pants.jpeg"
+ },
+ {
+ "code": "thumbnail",
+ "path": "\/pants.jpeg",
+ "cachedPath": "http:\/\/localhost\/media\/cache\/sylius_shop_api\/pants.jpeg"
+ }
+ ],
+ "_links": {
+ "self": {
+ "href": "\/shop-api\/products\/by-slug\/logan-t-shirt"
+ }
+ }
+ },
+ {
+ "code": "LOGAN_HAT_CODE",
+ "name": "Logan Hat",
+ "slug": "logan-hat",
+ "channelCode": "WEB_GB",
+ "description": "Some description Lorem ipsum dolor sit amet.",
+ "averageRating": 0,
+ "taxons": {
+ "main": "HAT",
+ "others": [
+ "HAT",
+ "BRAND"
+ ]
+ },
+ "variants": {
+ "SMALL_RED_LOGAN_HAT_CODE": {
+ "code": "SMALL_RED_LOGAN_HAT_CODE",
+ "name": "Small Red Logan Hat",
+ "axis": [
+ "HAT_SIZE_S",
+ "HAT_COLOR_RED"
+ ],
+ "nameAxis": {
+ "HAT_SIZE_S": "Size S",
+ "HAT_COLOR_RED": "Color Red"
+ },
+ "price": {
+ "current": 500,
+ "currency": "GBP"
+ },
+ "images": []
+ },
+ "LARGE_RED_LOGAN_HAT_CODE": {
+ "code": "LARGE_RED_LOGAN_HAT_CODE",
+ "name": "Large Red Logan Hat",
+ "axis": [
+ "HAT_SIZE_L",
+ "HAT_COLOR_RED"
+ ],
+ "nameAxis": {
+ "HAT_SIZE_L": "Size L",
+ "HAT_COLOR_RED": "Color Red"
+ },
+ "price": {
+ "current": 999,
+ "currency": "GBP"
+ },
+ "images": []
+ },
+ "SMALL_BLUE_LOGAN_HAT_CODE": {
+ "code": "SMALL_BLUE_LOGAN_HAT_CODE",
+ "name": "Small Blue Logan Hat",
+ "axis": [
+ "HAT_SIZE_S",
+ "HAT_COLOR_BLUE"
+ ],
+ "nameAxis": {
+ "HAT_SIZE_S": "Size S",
+ "HAT_COLOR_BLUE": "Color Blue"
+ },
+ "price": {
+ "current": 1500,
+ "currency": "GBP"
+ },
+ "images": []
+ },
+ "LARGE_BLUE_LOGAN_HAT_CODE": {
+ "code": "LARGE_BLUE_LOGAN_HAT_CODE",
+ "name": "Large Blue Logan Hat",
+ "axis": [
+ "HAT_SIZE_L",
+ "HAT_COLOR_BLUE"
+ ],
+ "nameAxis": {
+ "HAT_SIZE_L": "Size L",
+ "HAT_COLOR_BLUE": "Color Blue"
+ },
+ "price": {
+ "current": 2599,
+ "currency": "GBP"
+ },
+ "images": []
+ }
+ },
+ "attributes": [],
+ "associations": {
+ "CROSS_SELL_ASSOCIATION_TYPE": [
+ {
+ "code": "LOGAN_MUG_CODE",
+ "name": "Logan Mug",
+ "slug": "logan-mug",
+ "channelCode": "WEB_GB",
+ "description": "Some description Lorem ipsum dolor sit amet.",
+ "averageRating": 0,
+ "taxons": {
+ "main": "MUG",
+ "others": [
+ "MUG",
+ "BRAND"
+ ]
+ },
+ "variants": {
+ "LOGAN_MUG_CODE": {
+ "code": "LOGAN_MUG_CODE",
+ "name": "Logan Mug",
+ "axis": [],
+ "nameAxis": {},
+ "price": {
+ "current": 1999,
+ "currency": "GBP"
+ },
+ "originalPrice": {
+ "current": 2999,
+ "currency": "GBP"
+ },
+ "images": [
+ {
+ "code": "thumbnail",
+ "path": "\/pants.jpeg",
+ "cachedPath": "http:\/\/localhost\/media\/cache\/sylius_shop_api\/pants.jpeg"
+ }
+ ]
+ }
+ },
+ "attributes": [
+ {
+ "code": "MUG_MATERIAL_CODE",
+ "name": "Mug material",
+ "value": "Wood"
+ }
+ ],
+ "associations": [],
+ "images": [
+ {
+ "code": "thumbnail",
+ "path": "\/pants.jpeg",
+ "cachedPath": "http:\/\/localhost\/media\/cache\/sylius_shop_api\/pants.jpeg"
+ }
+ ],
+ "_links": {
+ "self": {
+ "href": "\/shop-api\/products\/by-slug\/logan-mug"
+ }
+ }
+ },
+ {
+ "code": "LOGAN_T_SHIRT_CODE",
+ "name": "Logan T-Shirt",
+ "slug": "logan-t-shirt",
+ "channelCode": "WEB_GB",
+ "description": "Some description Lorem ipsum dolor sit amet.",
+ "averageRating": 0,
+ "taxons": {
+ "main": "T_SHIRTS",
+ "others": [
+ "WOMEN_T_SHIRTS",
+ "BRAND"
+ ]
+ },
+ "variants": {
+ "SMALL_LOGAN_T_SHIRT_CODE": {
+ "code": "SMALL_LOGAN_T_SHIRT_CODE",
+ "name": "Small Logan T-Shirt",
+ "axis": [],
+ "nameAxis": {},
+ "price": {
+ "current": 1999,
+ "currency": "GBP"
+ },
+ "images": [
+ {
+ "code": "thumbnail",
+ "path": "\/pants.jpeg",
+ "cachedPath": "http:\/\/localhost\/media\/cache\/sylius_shop_api\/pants.jpeg"
+ }
+ ]
+ },
+ "LARGE_LOGAN_T_SHIRT_CODE": {
+ "code": "LARGE_LOGAN_T_SHIRT_CODE",
+ "name": "Large Logan T-Shirt",
+ "axis": [],
+ "nameAxis": {},
+ "price": {
+ "current": 2999,
+ "currency": "GBP"
+ },
+ "images": [
+ {
+ "code": "thumbnail",
+ "path": "\/pants.jpeg",
+ "cachedPath": "http:\/\/localhost\/media\/cache\/sylius_shop_api\/pants.jpeg"
+ }
+ ]
+ }
+ },
+ "attributes": [],
+ "associations": [],
+ "images": [
+ {
+ "code": "thumbnail",
+ "path": "\/pants.jpeg",
+ "cachedPath": "http:\/\/localhost\/media\/cache\/sylius_shop_api\/pants.jpeg"
+ },
+ {
+ "code": "thumbnail",
+ "path": "\/pants.jpeg",
+ "cachedPath": "http:\/\/localhost\/media\/cache\/sylius_shop_api\/pants.jpeg"
+ },
+ {
+ "code": "thumbnail",
+ "path": "\/pants.jpeg",
+ "cachedPath": "http:\/\/localhost\/media\/cache\/sylius_shop_api\/pants.jpeg"
+ }
+ ],
+ "_links": {
+ "self": {
+ "href": "\/shop-api\/products\/by-slug\/logan-t-shirt"
+ }
+ }
+ }
+ ]
+ },
+ "images": [],
+ "_links": {
+ "self": {
+ "href": "\/shop-api\/products\/by-slug\/logan-hat"
+ }
+ }
+ },
+ {
+ "code": "LOGAN_SHOES_CODE",
+ "name": "Logan Shoes",
+ "slug": "logan-shoes",
+ "channelCode": "WEB_GB",
+ "description": "Some description Lorem ipsum dolor sit amet.",
+ "shortDescription": "Short description Lorem ipsum dolor sit amet.",
+ "averageRating": 0,
+ "taxons": {
+ "others": []
+ },
+ "variants": [],
+ "attributes": [],
+ "associations": [],
+ "images": [],
+ "_links": {
+ "self": {
+ "href": "\/shop-api\/products\/by-slug\/logan-shoes"
+ }
+ }
+ }
+ ]
+}
diff --git a/tests/Responses/Expected/product/product_list_page_by_phrase_mug_including_short_description_response.json b/tests/Responses/Expected/product/product_list_page_by_phrase_mug_including_short_description_response.json
new file mode 100644
index 000000000..cdff9f82d
--- /dev/null
+++ b/tests/Responses/Expected/product/product_list_page_by_phrase_mug_including_short_description_response.json
@@ -0,0 +1,35 @@
+{
+ "page": 1,
+ "limit": 10,
+ "pages": 1,
+ "total": 1,
+ "_links": {
+ "self": "\/shop-api\/products\/by-phrase\/short?includeDescription=1&page=1&limit=10",
+ "first": "\/shop-api\/products\/by-phrase\/short?includeDescription=1&page=1&limit=10",
+ "last": "\/shop-api\/products\/by-phrase\/short?includeDescription=1&page=1&limit=10",
+ "next": "\/shop-api\/products\/by-phrase\/short?includeDescription=1&page=1&limit=10"
+ },
+ "items": [
+ {
+ "code": "LOGAN_SHOES_CODE",
+ "name": "Logan Shoes",
+ "slug": "logan-shoes",
+ "channelCode": "WEB_GB",
+ "description": "Some description Lorem ipsum dolor sit amet.",
+ "shortDescription": "Short description Lorem ipsum dolor sit amet.",
+ "averageRating": 0,
+ "taxons": {
+ "others": []
+ },
+ "variants": [],
+ "attributes": [],
+ "associations": [],
+ "images": [],
+ "_links": {
+ "self": {
+ "href": "\/shop-api\/products\/by-slug\/logan-shoes"
+ }
+ }
+ }
+ ]
+}
diff --git a/tests/Responses/Expected/product/product_list_page_by_phrase_mug_response.json b/tests/Responses/Expected/product/product_list_page_by_phrase_mug_response.json
new file mode 100644
index 000000000..2281fdfab
--- /dev/null
+++ b/tests/Responses/Expected/product/product_list_page_by_phrase_mug_response.json
@@ -0,0 +1,72 @@
+{
+ "page": 1,
+ "limit": 10,
+ "pages": 1,
+ "total": 1,
+ "_links": {
+ "self": "\/shop-api\/products\/by-phrase\/mug?page=1&limit=10",
+ "first": "\/shop-api\/products\/by-phrase\/mug?page=1&limit=10",
+ "last": "\/shop-api\/products\/by-phrase\/mug?page=1&limit=10",
+ "next": "\/shop-api\/products\/by-phrase\/mug?page=1&limit=10"
+ },
+ "items": [
+ {
+ "code": "LOGAN_MUG_CODE",
+ "name": "Logan Mug",
+ "slug": "logan-mug",
+ "channelCode": "WEB_GB",
+ "description": "Some description Lorem ipsum dolor sit amet.",
+ "averageRating": 0,
+ "taxons": {
+ "main": "MUG",
+ "others": [
+ "MUG",
+ "BRAND"
+ ]
+ },
+ "variants": {
+ "LOGAN_MUG_CODE": {
+ "code": "LOGAN_MUG_CODE",
+ "name": "Logan Mug",
+ "axis": [],
+ "nameAxis": {},
+ "price": {
+ "current": 1999,
+ "currency": "GBP"
+ },
+ "originalPrice": {
+ "current": 2999,
+ "currency": "GBP"
+ },
+ "images": [
+ {
+ "code": "thumbnail",
+ "path": "\/pants.jpeg",
+ "cachedPath": "http:\/\/localhost\/media\/cache\/sylius_shop_api\/pants.jpeg"
+ }
+ ]
+ }
+ },
+ "attributes": [
+ {
+ "code": "MUG_MATERIAL_CODE",
+ "name": "Mug material",
+ "value": "Wood"
+ }
+ ],
+ "associations": [],
+ "images": [
+ {
+ "code": "thumbnail",
+ "path": "\/pants.jpeg",
+ "cachedPath": "http:\/\/localhost\/media\/cache\/sylius_shop_api\/pants.jpeg"
+ }
+ ],
+ "_links": {
+ "self": {
+ "href": "\/shop-api\/products\/by-slug\/logan-mug"
+ }
+ }
+ }
+ ]
+}
diff --git a/tests/Responses/Expected/product/product_without_taxons_details_page.json b/tests/Responses/Expected/product/product_without_taxons_details_page.json
index e7602bd11..022bb44eb 100644
--- a/tests/Responses/Expected/product/product_without_taxons_details_page.json
+++ b/tests/Responses/Expected/product/product_without_taxons_details_page.json
@@ -5,6 +5,7 @@
"channelCode": "WEB_GB",
"breadcrumb": "logan-shoes",
"description": "Some description Lorem ipsum dolor sit amet.",
+ "shortDescription": "Short description Lorem ipsum dolor sit amet.",
"averageRating": 0,
"taxons": {
"others": []