Installation:
composer require akeneo/measure-bundle
Add to AppKernel.php (Symfony <4.4) or config/bundles.php (Symfony ≥4.4):
new Akeneo\Bundle\MeasureBundle\AkeneoMeasureBundle(),
Basic Configuration:
Override Resources/config/measure.yml in your bundle to extend or replace default measures:
akeneo_measure:
measures_config:
Length:
standard: METER
units: { ... }
First Conversion: Inject the converter service and use it:
$converter = $this->container->get('akeneo_measure.measure_converter');
$converter->setFamily('Length'); // Set family first
$result = $converter->convert('KILOMETER', 'MILE', 1); // 1km → 0.621371 miles
Family Selection:
Always call setFamily() before conversions. Families are case-sensitive strings (e.g., 'Length').
$converter->setFamily('Length');
Conversion Pipeline:
$converter->convert('from_unit', 'to_unit', $value);
Dynamic Configuration:
Extend measures via YAML (e.g., config/packages/akeneo_measure.yml):
akeneo_measure:
measures_config:
CustomFamily:
standard: BASE_UNIT
units:
NEW_UNIT:
convert: [{'mul': 2}, {'add': 10}]
symbol: "nu"
Form Handling: Use the bundle to validate/convert user inputs (e.g., product dimensions):
$converter->setFamily('Length');
$convertedValue = $converter->convert('CUSTOM_UNIT', 'METER', $request->get('dimension'));
API Responses: Normalize units in API responses:
$product->setDimension(
$converter->convert($product->getDimensionUnit(), 'CENTIMETER', $product->getDimension())
);
Database Storage:
Store values in a standard unit (e.g., METER) and convert on-the-fly for display:
$converter->setFamily('Length');
$displayValue = $converter->convert('METER', 'FOOT', $product->dimension);
Symfony Forms:
Use ChoiceType with dynamic unit options:
$form->add('unit', ChoiceType::class, [
'choices' => array_flip($this->getMeasureUnits('Length')),
]);
Family Not Set:
Forgetting setFamily() throws UnknownFamilyMeasureException. Always set it first.
Case Sensitivity:
Families/units are case-sensitive (e.g., 'length' ≠ 'Length').
Division by Zero:
The bundle silently ignores invalid operations (e.g., div: 0). Validate inputs:
if ($denominator === 0) {
throw new \RuntimeException("Invalid conversion: division by zero.");
}
Circular Dependencies:
Avoid defining units where A → B → A creates infinite loops in conversions.
Configuration Overrides:
Later YAML configs merge with defaults. Use !replace in Symfony ≥3.3 to force overrides:
akeneo_measure:
measures_config: !replace { %akeneo_measure.measures_config%: { ... } }
Check Config: Dump the loaded config to verify units/families:
$config = $this->container->getParameter('akeneo_measure.measures_config');
dd($config['Length']['units']);
Log Conversions: Wrap conversions in a service to log operations:
$this->logger->debug(
'Converting {value} {from} → {to}',
['value' => $value, 'from' => $from, 'to' => $to]
);
Unit Tests: Test edge cases (e.g., zero values, invalid units):
$this->expectException(UnknownMeasureException::class);
$converter->convert('INVALID_UNIT', 'METER', 1);
Custom Operators:
Extend the converter to support new operations (e.g., pow):
// In a service extending MeasureConverter
protected function applyOperation($value, $operator, $operand) {
if ($operator === 'pow') {
return pow($value, $operand);
}
// ... default logic
}
Dynamic Config Loading: Load measures from a database or API:
# config/services.yaml
akeneo_measure.measure_converter:
arguments: ['@app.measure_config_loader']
// src/Service/MeasureConfigLoader.php
class MeasureConfigLoader implements \Countable {
public function count() { /* ... */ }
public function offsetExists($offset) { /* ... */ }
public function offsetGet($offset) { /* Load from DB/API */ }
}
Symfony Cache: Cache the converter’s configuration for performance:
# config/packages/cache.yaml
akeneo_measure.measures_config:
cache: cache.app
Validation: Add constraints to Symfony forms:
use Akeneo\Bundle\MeasureBundle\Validator\Constraints\ValidMeasure;
$builder->add('value', TextType::class, [
'constraints' => [
new ValidMeasure(['family' => 'Length', 'unit' => 'METER']),
],
]);
How can I help you explore Laravel packages today?