Skip to content

IBX-9147: Symbol attribute type described in Developer Documentation - v5.0 #2826

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Jul 22, 2025
Merged
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
@@ -0,0 +1,9 @@
<?php declare(strict_types=1);

use Ibexa\Contracts\ProductCatalog\Values\Product\ProductQuery;
use Ibexa\Contracts\ProductCatalogSymbolAttribute\Search\Criterion\SymbolAttribute;

$query = new ProductQuery();
$query->setFilter(new SymbolAttribute('ean', ['5023920187205']));
/** @var \Ibexa\Contracts\ProductCatalog\ProductServiceInterface $productService */
$results = $productService->findProducts($query);
46 changes: 46 additions & 0 deletions code_samples/pim/Symbol/Format/Checksum/LuhnChecksum.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

declare(strict_types=1);

namespace App\PIM\Symbol\Format\Checksum;

use Ibexa\Contracts\ProductCatalog\Values\AttributeDefinitionInterface;
use Ibexa\Contracts\ProductCatalogSymbolAttribute\Value\ChecksumInterface;

final class LuhnChecksum implements ChecksumInterface
{
public function validate(AttributeDefinitionInterface $attributeDefinition, string $value): bool
{
$digits = $this->getDigits($value);

$count = count($digits);
$total = 0;
for ($i = $count - 2; $i >= 0; $i -= 2) {
$digit = $digits[$i];
if ($i % 2 === 0) {
$digit *= 2;
}

$total += $digit > 9 ? $digit - 9 : $digit;
}

$checksum = $digits[$count - 1];

return $total + $checksum === 0;
}

/**
* Returns an array of digits from the given value (skipping any formatting characters).
*
* @return int[]
*/
private function getDigits(string $value): array
{
$chars = array_filter(
str_split($value),
static fn (string $char): bool => $char !== '-'
);

return array_map('intval', array_values($chars));
}
}
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@
"ibexa/tree-builder": "~5.0.x-dev",
"ibexa/discounts": "~5.0.x-dev",
"ibexa/discounts-codes": "~5.0.x-dev",
"ibexa/core-search": "~5.0.x-dev"
"ibexa/core-search": "~5.0.x-dev",
"ibexa/product-catalog-symbol-attribute": "~5.0.x-dev"
},
"scripts": {
"fix-cs": "php-cs-fixer fix --config=.php-cs-fixer.php -v --show-progress=dots",
Expand Down
87 changes: 87 additions & 0 deletions docs/pim/attributes/symbol_attribute_type.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
---

Check warning on line 1 in docs/pim/attributes/symbol_attribute_type.md

View workflow job for this annotation

GitHub Actions / vale

[vale] docs/pim/attributes/symbol_attribute_type.md#L1

[Ibexa.ReadingLevel] The grade level is 9.31. Aim for 8th grade or lower by using shorter sentences and words.
Raw output
{"message": "[Ibexa.ReadingLevel] The grade level is 9.31. Aim for 8th grade or lower by using shorter sentences and words.", "location": {"path": "docs/pim/attributes/symbol_attribute_type.md", "range": {"start": {"line": 1, "column": 1}}}, "severity": "WARNING"}
description: Create a symbol attribute type that enables for the efficient representation of string-based values while enforcing their format in product specifications.
---

# Symbol attribute type

In product specifications, the symbol attribute type enables the efficient representation of string-based data and enforces their format.

This feature allows you to store standard product identifiers (such as EAN or ISBN) in the [Product Information Management](pim_guide.md) system.

## Build-in symbol attribute formats

The built-in symbol attribute formats in `ibexa/product-catalog-symbol-attribute` are listed below:

| Name | Description | Example |
|-----------------|-----------------|-----------------|
| Generic | Accepts any string value | #FR1.2 |
| Generic (alphabetic characters only) | Accepts any string value that contais only letters | ABCD |
| Generic (digits only) | Accepts any string value that contais only digits | 123456 |
| Generic (alphanumeric characters only) | Accepts any string value that contains only letters or digits | 2N6405G |
| Generic (hexadecimal digits only) | Accepts any string value that contains only hexadecimal digits (digits or A-F characters) | DEADBEEF |
| EAN-8 | European Article Number (8 characters) | 96385074 |
| EAN-13 | European Article Number (13 characters) | 5023920187205 |
| EAN-14 | European Article Number (14 characters) | 12345678901231 |
| ISBN-10 | International Standard Book Number (10 characters) | 0-19-852663-6 |
| ISBN-13 | International Standard Book Number (13 characters) | 978-1-86197-876-9 |

!!! caution

Maximum length of the symbol value is 160 characters.

## Create custom symbol attribute format

Under the `ibexa_product_catalog_symbol_attribute.formats` key, you can use configuration to create your own symbol format.

See the example below:

``` yaml
ibexa_product_catalog_symbol_attribute:
formats:
manufacturer_part_number:
name: 'Manufacturer Part Number'
pattern: '/^[A-Z]{3}-\d{5}$/'
examples:
- 'RPI-14645'
- 'MSS-24827'
- 'SEE-15444'
```
This following example specifies the format for a "Manufacturer Part Number", defined with the `manufacturer_part_number` identifier.

The pattern is specified using a regular expression.
According to the pattern option, the attribute value:

- must be a string
- begins with three capital letters (A-Z), followed by a hyphen ("-")
- ends with five digits (0-9), with no other characters before or after

Certain formats, such as the International Standard Book Number (ISBN-10) and the European Article Number (EAN-13), contain checksum digits and are self-validating.

To validate checksum of symbol:

1\. Create a class implementing the `\Ibexa\Contracts\ProductCatalogSymbolAttribute\Value\ChecksumInterface` interface.

2\. Register the class as a service using the `ibexa.product_catalog.attribute.symbol.checksum` tag and specify the format identifier using the `format` attribute.

See below the example implementation of checksum validation using Luhn formula:

``` php
[[= include_file('code_samples/pim/Symbol/Format/Checksum/LuhnChecksum.php') =]]
```

Example service definition:

``` yaml
services:
App\PIM\Symbol\Format\Checksum\LuhnChecksum:
tags:
- name: ibexa.product_catalog.attribute.symbol.checksum
format: my_format
```
The format attribute (`my_format`) is the identifier used under the `ibexa_product_catalog_symbol_attribute.formats` key.

## Search for products with given symbol attribute

You can use `SymbolAttribute` Search Criterion to find products by symbol attribute:

For more information, see [SymbolAttribute Criterion](symbolattribute_criterion.md).
2 changes: 1 addition & 1 deletion docs/search/criteria_reference/product_search_criteria.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,4 @@ Search Criterion let you filter product by specific attributes, for example, col
|[RangeMeasurementAttributeMinimum](rangemeasurementattributeminimum_criterion.md)|Minimum value of product's measurement attribute|
|[SelectionAttribute](selectionattribute_criterion.md)|Value of product's selection attribute|
|[SimpleMeasurementAttribute](simplemeasurementattribute_criterion.md)|Value of product's measurement attribute|

|[SymbolAttribute](symbolattribute_criterion.md)|Value of product's symbol attribute|
20 changes: 20 additions & 0 deletions docs/search/criteria_reference/symbolattribute_criterion.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---

Check warning on line 1 in docs/search/criteria_reference/symbolattribute_criterion.md

View workflow job for this annotation

GitHub Actions / vale

[vale] docs/search/criteria_reference/symbolattribute_criterion.md#L1

[Ibexa.ReadingLevel] The grade level is 6.58. Aim for 8th grade or lower by using shorter sentences and words.
Raw output
{"message": "[Ibexa.ReadingLevel] The grade level is 6.58. Aim for 8th grade or lower by using shorter sentences and words.", "location": {"path": "docs/search/criteria_reference/symbolattribute_criterion.md", "range": {"start": {"line": 1, "column": 1}}}, "severity": "WARNING"}
description: SymbolAttribute Criterion
---

# SymbolAttributeCriterion

The `SymbolAttribute` Search Criterion searches for products by [symbol attribute](symbol_attribute_type.md).

## Arguments

- `identifier` - identifier of the format
- `value` - array with the values to search for

## Example

### PHP

``` php
[[= include_file('code_samples/back_office/search/src/Query/SymbolAttributeTypeQuery.php') =]]
```
2 changes: 2 additions & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,7 @@ nav:
- Products: pim/products.md
- Attributes:
- Date and Time attribute: pim/attributes/date_and_time.md
- Symbol attribute type: pim/attributes/symbol_attribute_type.md
- Product API: pim/product_api.md
- Catalogs: pim/catalogs.md
- Catalog API: pim/catalog_api.md
Expand Down Expand Up @@ -589,6 +590,7 @@ nav:
- RangeMeasurementAttributeMaximum: search/criteria_reference/rangemeasurementattributemaximum_criterion.md
- SimpleMeasurementAttribute: search/criteria_reference/simplemeasurementattribute_criterion.md
- SelectionAttribute: search/criteria_reference/selectionattribute_criterion.md
- SymbolAttribute: search/criteria_reference/symbolattribute_criterion.md
- Order Search Criteria:
- Order Search Criteria: search/criteria_reference/order_search_criteria.md
- CompanyName: search/criteria_reference/order_company_name_criterion.md
Expand Down
Loading