diff --git a/config/class.yaml b/config/class.yaml
index 1de06806..e818c5e5 100644
--- a/config/class.yaml
+++ b/config/class.yaml
@@ -17,6 +17,11 @@ services:
Pimcore\Bundle\StudioBackendBundle\Class\Service\FieldCollection\LayoutDefinitionServiceInterface:
class: Pimcore\Bundle\StudioBackendBundle\Class\Service\FieldCollection\LayoutDefinitionService
+ Pimcore\Bundle\StudioBackendBundle\Class\Repository\QuantityValueRepositoryInterface:
+ class: Pimcore\Bundle\StudioBackendBundle\Class\Repository\QuantityValueRepository
+
+ Pimcore\Bundle\StudioBackendBundle\Class\Service\QuantityValueServiceInterface:
+ class: Pimcore\Bundle\StudioBackendBundle\Class\Service\QuantityValueService
#
# Hydrators
diff --git a/src/Class/Attribute/Request/ConvertRequestBody.php b/src/Class/Attribute/Request/ConvertRequestBody.php
new file mode 100644
index 00000000..799e4800
--- /dev/null
+++ b/src/Class/Attribute/Request/ConvertRequestBody.php
@@ -0,0 +1,34 @@
+value)]
+ #[Post(
+ path: self::PREFIX . '/class/quantity-value/convert-all',
+ operationId: 'class_quantity_value_unit_convert_all',
+ description: 'class_quantity_value_unit_convert_all_description',
+ summary: 'class_quantity_value_unit_convert_all_summary',
+ tags: [Tags::ClassDefinition->value]
+ )]
+ #[SuccessResponse(
+ description: 'class_quantity_value_unit_convert_all_success_response',
+ content: new JsonContent(ref: ConvertedQuantityValues::class)
+ )]
+ #[ConvertRequestBody(ConvertAllParameters::class)]
+ #[DefaultResponses([
+ HttpResponseCodes::UNAUTHORIZED,
+ HttpResponseCodes::NOT_FOUND,
+ ])]
+ public function covertAll(#[MapRequestPayload] ConvertAllParameters $parameters): JsonResponse
+ {
+ return $this->jsonResponse($this->quantityValueService->convertAllUnits($parameters));
+ }
+}
diff --git a/src/Class/Controller/QuantityValue/ConvertController.php b/src/Class/Controller/QuantityValue/ConvertController.php
new file mode 100644
index 00000000..b68fd81f
--- /dev/null
+++ b/src/Class/Controller/QuantityValue/ConvertController.php
@@ -0,0 +1,83 @@
+value)]
+ #[Post(
+ path: self::PREFIX . '/class/quantity-value/convert',
+ operationId: 'class_quantity_value_unit_convert',
+ description: 'class_quantity_value_unit_convert_description',
+ summary: 'class_quantity_value_unit_convert_summary',
+ tags: [Tags::ClassDefinition->value]
+ )]
+ #[SuccessResponse(
+ description: 'class_quantity_value_unit_convert_success_response',
+ content: new ConvertedValueJson()
+ )]
+ #[ConvertRequestBody]
+ #[DefaultResponses([
+ HttpResponseCodes::UNAUTHORIZED,
+ HttpResponseCodes::NOT_FOUND,
+ ])]
+ public function convert(#[MapRequestPayload] ConvertParameters $parameters): JsonResponse
+ {
+ return $this->jsonResponse(['data' => $this->quantityValueService->convertUnit($parameters)]);
+ }
+}
diff --git a/src/Class/Controller/QuantityValue/UnitListController.php b/src/Class/Controller/QuantityValue/UnitListController.php
new file mode 100644
index 00000000..b6e26905
--- /dev/null
+++ b/src/Class/Controller/QuantityValue/UnitListController.php
@@ -0,0 +1,73 @@
+value)]
+ #[Get(
+ path: self::PREFIX . '/class/quantity-value/unit-list',
+ operationId: 'class_quantity_value_unit_list',
+ description: 'class_quantity_value_unit_list_description',
+ summary: 'class_quantity_value_unit_list_summary',
+ tags: [Tags::ClassDefinition->value]
+ )]
+ #[SuccessResponse(
+ description: 'class_quantity_value_unit_list_success_response',
+ content: new QuantityValueUnitsJson()
+ )]
+ #[DefaultResponses([
+ HttpResponseCodes::UNAUTHORIZED,
+ ])]
+ public function listUnits(): JsonResponse
+ {
+ return $this->jsonResponse(['items' => $this->quantityValueService->listUnits()]);
+ }
+}
diff --git a/src/Class/Event/PreResponse/QuantityValueConversionEvent.php b/src/Class/Event/PreResponse/QuantityValueConversionEvent.php
new file mode 100644
index 00000000..c9c0c15c
--- /dev/null
+++ b/src/Class/Event/PreResponse/QuantityValueConversionEvent.php
@@ -0,0 +1,39 @@
+collection);
+ }
+
+ /**
+ * Use this to get additional infos out of the response object
+ */
+ public function getCollection(): ConvertedQuantityValues
+ {
+ return $this->collection;
+ }
+}
diff --git a/src/Class/Event/PreResponse/QuantityValueUnitEvent.php b/src/Class/Event/PreResponse/QuantityValueUnitEvent.php
new file mode 100644
index 00000000..40f58c6b
--- /dev/null
+++ b/src/Class/Event/PreResponse/QuantityValueUnitEvent.php
@@ -0,0 +1,39 @@
+unit);
+ }
+
+ /**
+ * Use this to get additional infos out of the response object
+ */
+ public function getUnit(): QuantityValueUnit
+ {
+ return $this->unit;
+ }
+}
diff --git a/src/Class/Repository/QuantityValueRepository.php b/src/Class/Repository/QuantityValueRepository.php
new file mode 100644
index 00000000..9d01939d
--- /dev/null
+++ b/src/Class/Repository/QuantityValueRepository.php
@@ -0,0 +1,52 @@
+setOrderKey(['baseunit', 'factor', 'abbreviation']);
+ $list->setOrder(['ASC', 'ASC', 'ASC']);
+
+ return $list->getUnits();
+ }
+
+ /**
+ * @return Unit[]
+ */
+ public function getUnitListByBaseUnit(string $baseUnitId, string $fromUnitId): array
+ {
+ $list = new Listing();
+ $list->setCondition(
+ 'baseunit = ' . $list->quote($baseUnitId) .
+ ' AND id != ' . $list->quote($fromUnitId)
+ );
+
+ return $list->getUnits();
+ }
+}
diff --git a/src/Class/Repository/QuantityValueRepositoryInterface.php b/src/Class/Repository/QuantityValueRepositoryInterface.php
new file mode 100644
index 00000000..f68f2651
--- /dev/null
+++ b/src/Class/Repository/QuantityValueRepositoryInterface.php
@@ -0,0 +1,35 @@
+fromUnitId;
+ }
+
+ public function getValue(): float|int
+ {
+ return $this->value;
+ }
+}
diff --git a/src/Class/Schema/ConvertParameters.php b/src/Class/Schema/ConvertParameters.php
new file mode 100644
index 00000000..d63d0c04
--- /dev/null
+++ b/src/Class/Schema/ConvertParameters.php
@@ -0,0 +1,53 @@
+fromUnitId;
+ }
+
+ public function getToUnitId(): string
+ {
+ return $this->toUnitId;
+ }
+
+ public function getValue(): float|int
+ {
+ return $this->value;
+ }
+}
diff --git a/src/Class/Schema/ConvertedQuantityValue.php b/src/Class/Schema/ConvertedQuantityValue.php
new file mode 100644
index 00000000..900d8fea
--- /dev/null
+++ b/src/Class/Schema/ConvertedQuantityValue.php
@@ -0,0 +1,57 @@
+unitAbbreviation;
+ }
+
+ public function getUnitLongName(): string
+ {
+ return $this->unitLongName;
+ }
+
+ public function getConvertedValue(): float
+ {
+ return $this->convertedValue;
+ }
+}
diff --git a/src/Class/Schema/ConvertedQuantityValues.php b/src/Class/Schema/ConvertedQuantityValues.php
new file mode 100644
index 00000000..7b70c494
--- /dev/null
+++ b/src/Class/Schema/ConvertedQuantityValues.php
@@ -0,0 +1,70 @@
+originalValue;
+ }
+
+ public function getFromUnitId(): string
+ {
+ return $this->fromUnitId;
+ }
+
+ public function getConvertedValues(): array
+ {
+ return $this->convertedValues;
+ }
+}
diff --git a/src/Class/Schema/QuantityValueUnit.php b/src/Class/Schema/QuantityValueUnit.php
new file mode 100644
index 00000000..288ebc13
--- /dev/null
+++ b/src/Class/Schema/QuantityValueUnit.php
@@ -0,0 +1,109 @@
+id;
+ }
+
+ public function getAbbreviation(): ?string
+ {
+ return $this->abbreviation;
+ }
+
+ public function getGroup(): ?string
+ {
+ return $this->group;
+ }
+
+ public function getLongName(): ?string
+ {
+ return $this->longName;
+ }
+
+ public function getBaseUnit(): ?string
+ {
+ return $this->baseUnit;
+ }
+
+ public function getReference(): ?string
+ {
+ return $this->reference;
+ }
+
+ public function getFactor(): ?float
+ {
+ return $this->factor;
+ }
+
+ public function getConversionOffset(): ?float
+ {
+ return $this->conversionOffset;
+ }
+
+ public function getConverter(): ?string
+ {
+ return $this->converter;
+ }
+}
diff --git a/src/Class/Service/QuantityValueService.php b/src/Class/Service/QuantityValueService.php
new file mode 100644
index 00000000..3c602838
--- /dev/null
+++ b/src/Class/Service/QuantityValueService.php
@@ -0,0 +1,159 @@
+quantityValueRepository->getUnitList();
+ $units = [];
+
+ foreach ($listing as $unit) {
+ $quantityValueUnit = new QuantityValueUnit(
+ $unit->getId(),
+ $unit->getAbbreviation(),
+ $unit->getGroup(),
+ $unit->getLongname(),
+ $unit->getBaseunit() ? $unit->getBaseunit()->getId() : null,
+ $unit->getReference(),
+ $unit->getFactor(),
+ $unit->getConversionOffset(),
+ $unit->getConverter()
+ );
+
+ $this->eventDispatcher->dispatch(
+ new QuantityValueUnitEvent($quantityValueUnit),
+ QuantityValueUnitEvent::EVENT_NAME
+ );
+
+ $units[] = $quantityValueUnit;
+ }
+
+ return $units;
+ }
+
+ /**
+ * @throws DatabaseException|NotFoundException
+ */
+ public function convertUnit(ConvertParameters $parameters): float|int
+ {
+ return $this->getConvertedValue(
+ $this->getUnit($parameters->getFromUnitId()),
+ $this->getUnit($parameters->getToUnitId()),
+ $parameters->getValue()
+ );
+ }
+
+ /**
+ * @throws DatabaseException|NotFoundException
+ */
+ public function convertAllUnits(ConvertAllParameters $parameters): ConvertedQuantityValues
+ {
+ $fromUnit = $this->getUnit($parameters->getFromUnitId());
+ $baseUnit = $fromUnit->getBaseunit() ?? $fromUnit;
+ $toUnits = $this->quantityValueRepository->getUnitListByBaseUnit($baseUnit->getId(), $fromUnit->getId());
+
+ $convertedValues = [];
+ foreach ($toUnits as $toUnit) {
+ $convertedValue = $this->getConvertedValue($fromUnit, $toUnit, $parameters->getValue());
+ $convertedValues[] = new ConvertedQuantityValue(
+ $toUnit->getAbbreviation(),
+ $toUnit->getLongname(),
+ round($convertedValue, 4)
+ );
+ }
+
+ $collection = new ConvertedQuantityValues(
+ $parameters->getValue(),
+ $parameters->getFromUnitId(),
+ $convertedValues
+ );
+
+ $this->eventDispatcher->dispatch(
+ new QuantityValueConversionEvent($collection),
+ QuantityValueConversionEvent::EVENT_NAME
+ );
+
+ return $collection;
+ }
+
+ /**
+ * @throws NotFoundException
+ */
+ private function getUnit(string $unitId): Unit
+ {
+ $unit = $this->unitResolver->getById($unitId);
+
+ if ($unit === null) {
+ throw new NotFoundException('Unit', $unitId);
+ }
+
+ return $unit;
+ }
+
+ /**
+ * @throws DatabaseException
+ */
+ private function getConvertedValue(Unit $fromUnit, Unit $toUnit, float|int $value): float|int
+ {
+ try {
+ $convertedValue = $this->unitConversionService->convert(
+ new QuantityValue($value, $fromUnit),
+ $toUnit
+ );
+ } catch (Exception $exception) {
+ throw new DatabaseException(
+ sprintf('Could not convert unit "%s" to "%s": %s', $fromUnit, $toUnit, $exception->getMessage())
+ );
+ }
+
+ return $convertedValue->getValue();
+ }
+}
diff --git a/src/Class/Service/QuantityValueServiceInterface.php b/src/Class/Service/QuantityValueServiceInterface.php
new file mode 100644
index 00000000..553005f8
--- /dev/null
+++ b/src/Class/Service/QuantityValueServiceInterface.php
@@ -0,0 +1,45 @@
+{value} from one unit to another based on the given {fromUnitId} and {toUnitId}
+class_quantity_value_unit_convert_summary: Convert quantity value from one unit to another
+class_quantity_value_unit_convert_success_response: Converted quantity value
+class_quantity_value_unit_convert_all_description: |
+ Convert quantity {value} from one unit to all other available units based on the given {fromUnitId}.
+ Units have to have {fromUnitId} defined as base unit to be considered for conversion.
+class_quantity_value_unit_convert_all_summary: Convert quantity value from one unit to all other related units
+class_quantity_value_unit_convert_all_success_response: Converted quantity value
\ No newline at end of file