Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
use Ibexa\Contracts\ProductCatalog\Local\LocalProductServiceInterface;
use Ibexa\Contracts\ProductCatalog\Local\Values\Product\ProductVariantCreateStruct;
use Ibexa\Contracts\ProductCatalog\ProductServiceInterface;
use Ibexa\Contracts\ProductCatalog\Values\Content\Query\Criterion\ProductCriterionAdapter;
use Ibexa\Contracts\ProductCatalog\Values\Product\ProductVariantQuery;
use Ibexa\Contracts\ProductCatalog\Values\Product\Query\Criterion;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
Expand Down Expand Up @@ -46,12 +48,24 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$productCode = $input->getArgument('productCode');
$product = $this->productService->getProduct($productCode);

// Get variants
$variantQuery = new ProductVariantQuery(0, 5);
// Get variants filtered by variant codes
$codeQuery = new ProductVariantQuery();
$codeQuery->setVariantCodes(['DESK1', 'DESK2']);
$specificVariants = $this->productService->findProductVariants($product, $codeQuery)->getVariants();

$variants = $this->productService->findProductVariants($product, $variantQuery)->getVariants();
// Get variants with specific attributes
$combinedQuery = new ProductVariantQuery();
$combinedQuery->setAttributesCriterion(
new ProductCriterionAdapter(
new Criterion\LogicalAnd([
new Criterion\ColorAttribute('color', ['red', 'blue']),
new Criterion\IntegerAttribute('size', 42),
])
)
);
$filteredVariants = $this->productService->findProductVariants($product, $combinedQuery)->getVariants();

foreach ($variants as $variant) {
foreach ($specificVariants as $variant) {
$output->writeln($variant->getName());
$attributes = $variant->getDiscriminatorAttributes();
foreach ($attributes as $attribute) {
Expand All @@ -67,6 +81,24 @@ protected function execute(InputInterface $input, OutputInterface $output): int

$this->localProductService->createProductVariants($product, $variantCreateStructs);

// Search variants across all products
$query = new ProductVariantQuery();
$query->setVariantCodes(['DESK1', 'DESK2']);
$variantList = $this->productService->findVariants($query);

foreach ($variantList->getVariants() as $variant) {
$output->writeln($variant->getName());
}

// Search variants with attribute criterion
$colorQuery = new ProductVariantQuery();
$colorQuery->setAttributesCriterion(
new ProductCriterionAdapter(
new Criterion\ColorAttribute('color', ['red'])
)
);
$redVariants = $this->productService->findVariants($colorQuery);

return self::SUCCESS;
}
}
29 changes: 22 additions & 7 deletions docs/pim/product_api.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,20 +58,35 @@

### Product variants

You can access the variants of a product by using `ProductServiceInterface::findProductVariants()`.
You can access the variants of a product by using [`ProductServiceInterface::findProductVariants()`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-ProductCatalog-ProductServiceInterface.html#method_findProductVariants).

Check failure on line 61 in docs/pim/product_api.md

View workflow job for this annotation

GitHub Actions / vale

[vale] docs/pim/product_api.md#L61

[Ibexa.VariablesGlobal] Use global variable '[[= product_name_base =]]' instead of 'Ibexa'
Raw output
{"message": "[Ibexa.VariablesGlobal] Use global variable '[[= product_name_base =]]' instead of 'Ibexa'", "location": {"path": "docs/pim/product_api.md", "range": {"start": {"line": 61, "column": 141}}}, "severity": "ERROR"}
The method takes the product object and a [`ProductVariantQuery`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-ProductCatalog-Values-Product-ProductVariantQuery.html) object as parameters.

A `ProductVariantQuery` lets you define the offset and limit of the variant query.
The default offset is 0, and limit is 25.
You can filter variants by variant codes or use product criteria:

``` php
[[= include_file('code_samples/api/product_catalog/src/Command/ProductVariantCommand.php', 49, 52) =]]
[[= include_file('code_samples/api/product_catalog/src/Command/ProductVariantCommand.php', 50, 66) =]]
```

From a variant ([`ProductVariantInterface`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-ProductCatalog-Values-ProductVariantInterface.html)), you can access the attributes that are used to generate the variant by using `ProductVariantInterface::getDiscriminatorAttributes()`.
From a variant ([`ProductVariantInterface`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-ProductCatalog-Values-ProductVariantInterface.html)), you can access the attributes that are used to generate the variant by using [`ProductVariantInterface::getDiscriminatorAttributes()`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-ProductCatalog-Values-ProductVariantInterface.html#method_getDiscriminatorAttributes).

Check failure on line 70 in docs/pim/product_api.md

View workflow job for this annotation

GitHub Actions / vale

[vale] docs/pim/product_api.md#L70

[Ibexa.VariablesGlobal] Use global variable '[[= product_name_base =]]' instead of 'Ibexa'
Raw output
{"message": "[Ibexa.VariablesGlobal] Use global variable '[[= product_name_base =]]' instead of 'Ibexa'", "location": {"path": "docs/pim/product_api.md", "range": {"start": {"line": 70, "column": 84}}}, "severity": "ERROR"}

``` php
[[= include_file('code_samples/api/product_catalog/src/Command/ProductVariantCommand.php', 53, 60) =]]
[[= include_file('code_samples/api/product_catalog/src/Command/ProductVariantCommand.php', 69, 73) =]]
```

See [Product Search Criteria](product_search_criteria.md) and [Product Sort Clauses](product_sort_clauses.md) references for more information about how to use the [`ProductVariantQuery`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-ProductCatalog-Values-Product-ProductVariantQuery.html) class.

Check failure on line 76 in docs/pim/product_api.md

View workflow job for this annotation

GitHub Actions / vale

[vale] docs/pim/product_api.md#L76

[Ibexa.VariablesGlobal] Use global variable '[[= product_name_base =]]' instead of 'Ibexa'
Raw output
{"message": "[Ibexa.VariablesGlobal] Use global variable '[[= product_name_base =]]' instead of 'Ibexa'", "location": {"path": "docs/pim/product_api.md", "range": {"start": {"line": 76, "column": 227}}}, "severity": "ERROR"}

#### Searching variants across products

To search for variants across all products, use [`ProductServiceInterface::findVariants()`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-ProductCatalog-ProductServiceInterface.html#method_findVariants)

Check failure on line 80 in docs/pim/product_api.md

View workflow job for this annotation

GitHub Actions / vale

[vale] docs/pim/product_api.md#L80

[Ibexa.VariablesGlobal] Use global variable '[[= product_name_base =]]' instead of 'Ibexa'
Raw output
{"message": "[Ibexa.VariablesGlobal] Use global variable '[[= product_name_base =]]' instead of 'Ibexa'", "location": {"path": "docs/pim/product_api.md", "range": {"start": {"line": 80, "column": 132}}}, "severity": "ERROR"}
This method takes a [`ProductVariantQuery`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-ProductCatalog-Values-Product-ProductVariantQuery.html) object and returns variants regardless of their base product.

Check failure on line 81 in docs/pim/product_api.md

View workflow job for this annotation

GitHub Actions / vale

[vale] docs/pim/product_api.md#L81

[Ibexa.VariablesGlobal] Use global variable '[[= product_name_base =]]' instead of 'Ibexa'
Raw output
{"message": "[Ibexa.VariablesGlobal] Use global variable '[[= product_name_base =]]' instead of 'Ibexa'", "location": {"path": "docs/pim/product_api.md", "range": {"start": {"line": 81, "column": 84}}}, "severity": "ERROR"}

Unlike `findProductVariants()`, which requires a specific product object, `findVariants()` allows you to search the entire variant catalog.

You can filter variants using Product Criteria wrapped in a [`ProductCriterionAdapter`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-ProductCatalog-Values-Content-Query-Criterion-ProductCriterionAdapter.html).

Check failure on line 85 in docs/pim/product_api.md

View workflow job for this annotation

GitHub Actions / vale

[vale] docs/pim/product_api.md#L85

[Ibexa.VariablesGlobal] Use global variable '[[= product_name_base =]]' instead of 'Ibexa'
Raw output
{"message": "[Ibexa.VariablesGlobal] Use global variable '[[= product_name_base =]]' instead of 'Ibexa'", "location": {"path": "docs/pim/product_api.md", "range": {"start": {"line": 85, "column": 128}}}, "severity": "ERROR"}
For example, search for variants with specific product codes or attribute values:

``` php
[[= include_file('code_samples/api/product_catalog/src/Command/ProductVariantCommand.php', 83, 100) =]]
```

#### Creating variants
Expand All @@ -81,7 +96,7 @@
`ProductVariantCreateStruct` specifies the attribute values and the code for the new variant.

``` php
[[= include_file('code_samples/api/product_catalog/src/Command/ProductVariantCommand.php', 62, 68) =]]
[[= include_file('code_samples/api/product_catalog/src/Command/ProductVariantCommand.php', 85, 91) =]]
```

### Product assets
Expand Down
9 changes: 9 additions & 0 deletions docs/release_notes/ibexa_dxp_v5.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@

<div class="release-notes" markdown="1">

<!-- draft release notes -->
#### Improved product variant querying

Product variant querying now supports filtering by variant codes and product attribute criteria.

You can now use [`ProductServiceInterface::findVariants()`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-ProductCatalog-ProductServiceInterface.html#method_findVariants) to search for variants across all products, regardless of their base product.

Check failure on line 18 in docs/release_notes/ibexa_dxp_v5.0.md

View workflow job for this annotation

GitHub Actions / vale

[vale] docs/release_notes/ibexa_dxp_v5.0.md#L18

[Ibexa.VariablesGlobal] Use global variable '[[= product_name_base =]]' instead of 'Ibexa'
Raw output
{"message": "[Ibexa.VariablesGlobal] Use global variable '[[= product_name_base =]]' instead of 'Ibexa'", "location": {"path": "docs/release_notes/ibexa_dxp_v5.0.md", "range": {"start": {"line": 18, "column": 100}}}, "severity": "ERROR"}

For more information, see [Product API - Searching variants](product_api.md#searching-variants-across-products).

[[% set version = 'v5.0.5' %]]

[[= release_note_entry_begin("Ibexa DXP " + version, '2026-01-15', ['Headless', 'Experience', 'Commerce']) =]]
Expand Down
5 changes: 4 additions & 1 deletion docs/search/criteria_reference/product_search_criteria.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@

# Product Search Criteria reference

Product Search Criteria are only supported by [Product Search (`ProductServiceInterface::findProduct`)](product_api.md#products).
Product Search Criteria are supported by [Product Search (`ProductServiceInterface::findProduct`)](product_api.md#products).

Search Criterion let you filter product by specific attributes, for example, color, availability, or price.

Product Search Criteria can also be used with `ProductVariantQuery` when wrapped in a [`ProductCriterionAdapter`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-ProductCatalog-Values-Content-Query-Criterion-ProductCriterionAdapter.html)

Check failure on line 12 in docs/search/criteria_reference/product_search_criteria.md

View workflow job for this annotation

GitHub Actions / vale

[vale] docs/search/criteria_reference/product_search_criteria.md#L12

[Ibexa.VariablesGlobal] Use global variable '[[= product_name_base =]]' instead of 'Ibexa'
Raw output
{"message": "[Ibexa.VariablesGlobal] Use global variable '[[= product_name_base =]]' instead of 'Ibexa'", "location": {"path": "docs/search/criteria_reference/product_search_criteria.md", "range": {"start": {"line": 12, "column": 154}}}, "severity": "ERROR"}

Check failure on line 12 in docs/search/criteria_reference/product_search_criteria.md

View workflow job for this annotation

GitHub Actions / vale

[vale] docs/search/criteria_reference/product_search_criteria.md#L12

[Ibexa.SpacePunctuation] Do not use a space before full stop, comma or quotation mark.
Raw output
{"message": "[Ibexa.SpacePunctuation] Do not use a space before full stop, comma or quotation mark.", "location": {"path": "docs/search/criteria_reference/product_search_criteria.md", "range": {"start": {"line": 12, "column": 245}}}, "severity": "ERROR"}
. See the [product variant search examples](product_api.md#searching-variants-across-products) for more information.

## Product Search Criteria

|Search Criterion|Search based on|
Expand Down
5 changes: 4 additions & 1 deletion docs/search/sort_clause_reference/product_sort_clauses.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@

# Product Sort Clauses

Product Sort Clauses are only supported by [Product Search (`ProductServiceInterface::findProduct`)](product_api.md#products).
Product Sort Clauses are supported by [Product Search (`ProductServiceInterface::findProduct`)](product_api.md#products).

By using Sort Clause you can filter product by specific attributes, for example: price, code, or availability.

Product Sort Clauses can also be used with `ProductVariantQuery` when wrapped in a [`ProductCriterionAdapter`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-ProductCatalog-Values-Content-Query-Criterion-ProductCriterionAdapter.html)

Check failure on line 12 in docs/search/sort_clause_reference/product_sort_clauses.md

View workflow job for this annotation

GitHub Actions / vale

[vale] docs/search/sort_clause_reference/product_sort_clauses.md#L12

[Ibexa.VariablesGlobal] Use global variable '[[= product_name_base =]]' instead of 'Ibexa'
Raw output
{"message": "[Ibexa.VariablesGlobal] Use global variable '[[= product_name_base =]]' instead of 'Ibexa'", "location": {"path": "docs/search/sort_clause_reference/product_sort_clauses.md", "range": {"start": {"line": 12, "column": 151}}}, "severity": "ERROR"}

Check failure on line 12 in docs/search/sort_clause_reference/product_sort_clauses.md

View workflow job for this annotation

GitHub Actions / vale

[vale] docs/search/sort_clause_reference/product_sort_clauses.md#L12

[Ibexa.SpacePunctuation] Do not use a space before full stop, comma or quotation mark.
Raw output
{"message": "[Ibexa.SpacePunctuation] Do not use a space before full stop, comma or quotation mark.", "location": {"path": "docs/search/sort_clause_reference/product_sort_clauses.md", "range": {"start": {"line": 12, "column": 242}}}, "severity": "ERROR"}
. See the [product variant search examples](../../pim/product_api.md#searching-variants-across-products) for more information.

| Sort Clause | Sorting based on |
|-----|-----|
|[BasePrice](baseprice_sort_clause.md)|Base product price|
Expand Down
12 changes: 12 additions & 0 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,18 @@ parameters:
count: 1
path: code_samples/api/product_catalog/src/Command/ProductPriceCommand.php

-
message: '#^Parameter \#1 \$criterion of method Ibexa\\Contracts\\ProductCatalog\\Values\\Product\\ProductVariantQuery\:\:setAttributesCriterion\(\) expects Ibexa\\Contracts\\ProductCatalog\\Values\\Content\\Query\\Criterion\\ProductCriterionAdapter\<Ibexa\\Contracts\\ProductCatalog\\Values\\Product\\Query\\CriterionInterface\>\|null, Ibexa\\Contracts\\ProductCatalog\\Values\\Content\\Query\\Criterion\\ProductCriterionAdapter\<Ibexa\\Contracts\\ProductCatalog\\Values\\Product\\Query\\Criterion\\ColorAttribute\> given\.$#'
identifier: argument.type
count: 1
path: code_samples/api/product_catalog/src/Command/ProductVariantCommand.php

-
message: '#^Parameter \#1 \$criterion of method Ibexa\\Contracts\\ProductCatalog\\Values\\Product\\ProductVariantQuery\:\:setAttributesCriterion\(\) expects Ibexa\\Contracts\\ProductCatalog\\Values\\Content\\Query\\Criterion\\ProductCriterionAdapter\<Ibexa\\Contracts\\ProductCatalog\\Values\\Product\\Query\\CriterionInterface\>\|null, Ibexa\\Contracts\\ProductCatalog\\Values\\Content\\Query\\Criterion\\ProductCriterionAdapter\<Ibexa\\Contracts\\ProductCatalog\\Values\\Product\\Query\\Criterion\\LogicalAnd\> given\.$#'
identifier: argument.type
count: 1
path: code_samples/api/product_catalog/src/Command/ProductVariantCommand.php

-
message: '#^Cannot call method getDateTime\(\) on Ibexa\\Contracts\\Calendar\\Event\|null\.$#'
identifier: method.nonObject
Expand Down
Loading