bramato / dimensionutility
A PHP package for handling and converting various units of measure (weight, dimension, liquid volume).
Requires
- php: ^8.1
- dvdoug/boxpacker: ^4.1
Requires (Dev)
- pestphp/pest: ^3.8
This package is auto-updated.
Last update: 2025-04-12 16:56:50 UTC
README
Dimension Utility Package
A simple PHP package for handling and converting various units of measure (weight, dimension, liquid volume).
Installation
You can install the package via Composer:
composer require bramato/dimensionutility
Usage
The package provides DTOs (Data Transfer Objects) and Conversion Services for three types of measurements: Weight, Dimension, and Liquid Volume.
Weight Conversion
<?php use Bramato\DimensionUtility\Dto\WeightDto; use Bramato\DimensionUtility\Enum\WeightEnum; use Bramato\DimensionUtility\Services\WeightConversionService; // Create a WeightDto $initialWeight = new WeightDto(10, WeightEnum::KILOGRAM); // Or using the static factory method (useful if unit comes from a string) // $initialWeight = WeightDto::create(10, 'KILOGRAM'); // Get the conversion service $conversionService = WeightConversionService::create($initialWeight); // Convert to another unit $convertedWeight = $conversionService->convert(WeightEnum::POUND); echo $initialWeight . " is equal to " . $convertedWeight; // Output: 10 KILOGRAM is equal to 22.0462 POUND // You can also use the shortcut method on the DTO echo $initialWeight->toKG(); // Converts to Kilogram (if not already) // Output: 10 KILOGRAM
Available Weight Units (WeightEnum
):
Enum Case | String Value |
---|---|
WeightEnum::MILLIGRAM |
'MILLIGRAM' |
WeightEnum::GRAM |
'GRAM' |
WeightEnum::KILOGRAM |
'KILOGRAM' |
WeightEnum::OUNCE |
'OUNCE' |
WeightEnum::POUND |
'POUND' |
WeightEnum::TON |
'TON' |
WeightEnum::STONE |
'STONE' |
WeightEnum::MICROGRAM |
'MICROGRAM' |
WeightEnum::NANOGRAM |
'NANOGRAM' |
WeightEnum::HUNDREDTHS_POUND |
'HUNDREDTHS_POUND' |
Dimension Conversion
<?php use Bramato\DimensionUtility\Dto\DimensionDto; use Bramato\DimensionUtility\Enum\DimensionEnum; use Bramato\DimensionUtility\Services\DimensionConversionService; // Create a DimensionDto $initialDimension = new DimensionDto(5, DimensionEnum::METER); // Or using the static factory method // $initialDimension = DimensionDto::create(5, 'METER'); // Get the conversion service $conversionService = DimensionConversionService::create($initialDimension); // Convert to another unit $convertedDimension = $conversionService->convert(DimensionEnum::FOOT); echo $initialDimension . " is equal to " . $convertedDimension; // Output: 5 METER is equal to 16.4042 FOOT // You can also use the shortcut method on the DTO echo $initialDimension->toCM(); // Converts to Centimeter // Output: 500 CENTIMETER
Available Dimension Units (DimensionEnum
):
Enum Case | String Value |
---|---|
DimensionEnum::INCH |
'INCH' |
DimensionEnum::CENTIMETER |
'CENTIMETER' |
DimensionEnum::METER |
'METER' |
DimensionEnum::KILOMETER |
'KILOMETER' |
DimensionEnum::FOOT |
'FOOT' |
DimensionEnum::YARD |
'YARD' |
DimensionEnum::MILE |
'MILE' |
DimensionEnum::MILLIMETER |
'MILLIMETER' |
DimensionEnum::MICROMETER |
'MICROMETER' |
DimensionEnum::NANOMETER |
'NANOMETER' |
DimensionEnum::DECIMETER |
'DECIMETER' |
Liquid Volume Conversion
<?php use Bramato\DimensionUtility\Dto\LiquidVolumeDto; use Bramato\DimensionUtility\Enum\LiquidVolumeEnum; use Bramato\DimensionUtility\Services\LiquidVolumeConversionService; // Create a LiquidVolumeDto $initialVolume = new LiquidVolumeDto(2, LiquidVolumeEnum::GAL); // Or using the static factory method // $initialVolume = LiquidVolumeDto::create(2, 'GAL'); // Get the conversion service $conversionService = LiquidVolumeConversionService::create($initialVolume); // Convert to another unit $convertedVolume = $conversionService->convert(LiquidVolumeEnum::L); echo $initialVolume . " is equal to " . $convertedVolume; // Output: 2 GAL is equal to 7.57082 L // You can also use the shortcut method on the DTO echo $initialVolume->toLT(); // Converts to Liter // Output: 7.57082 L
Available Liquid Volume Units (LiquidVolumeEnum
):
Enum Case | String Value |
---|---|
LiquidVolumeEnum::ML |
'ML' |
LiquidVolumeEnum::L |
'L' |
LiquidVolumeEnum::FL_OZ |
'FL_OZ' |
LiquidVolumeEnum::GAL |
'GAL' |
LiquidVolumeEnum::PT |
'PT' |
LiquidVolumeEnum::QT |
'QT' |
LiquidVolumeEnum::C |
'C' |
Area Conversion
<?php use Bramato\DimensionUtility\Dto\AreaDto; use Bramato\DimensionUtility\Enum\AreaEnum; use Bramato\DimensionUtility\Services\AreaConversionService; // Create an AreaDto $initialArea = new AreaDto(1.5, AreaEnum::HECTARE); // Or using the static factory method // $initialArea = AreaDto::create(1.5, 'HECTARE'); // Get the conversion service $conversionService = AreaConversionService::create($initialArea); // Convert to another unit $convertedArea = $conversionService->convert(AreaEnum::ACRE); echo $initialArea . " is equal to " . $convertedArea; // Output: 1.5 HECTARE is equal to 3.706580721 ACRE (approx) // You can also use the shortcut methods on the DTO echo $initialArea->toSQM(); // Converts to Square Meters // Output: 15000 SQ_METER echo $initialArea->toACRE(); // Converts to Acres // Output: 3.706580721 ACRE (approx)
Available Area Units (AreaEnum
):
Enum Case | String Value |
---|---|
AreaEnum::SQ_METER |
'SQ_METER' |
AreaEnum::SQ_KILOMETER |
'SQ_KILOMETER' |
AreaEnum::SQ_CENTIMETER |
'SQ_CENTIMETER' |
AreaEnum::SQ_MILLIMETER |
'SQ_MILLIMETER' |
AreaEnum::SQ_FOOT |
'SQ_FOOT' |
AreaEnum::SQ_YARD |
'SQ_YARD' |
AreaEnum::SQ_INCH |
'SQ_INCH' |
AreaEnum::SQ_MILE |
'SQ_MILE' |
AreaEnum::ACRE |
'ACRE' |
AreaEnum::HECTARE |
'HECTARE' |
Temperature Conversion
<?php use Bramato\DimensionUtility\Dto\TemperatureDto; use Bramato\DimensionUtility\Enum\TemperatureEnum; use Bramato\DimensionUtility\Services\TemperatureConversionService; // Create a TemperatureDto $initialTemp = new TemperatureDto(25, TemperatureEnum::CELSIUS); // Or using the static factory method // $initialTemp = TemperatureDto::create(25, 'CELSIUS'); // Get the conversion service $conversionService = TemperatureConversionService::create($initialTemp); // Convert to another unit $convertedTemp = $conversionService->convert(TemperatureEnum::FAHRENHEIT); echo $initialTemp . " is equal to " . $convertedTemp; // Output: 25 CELSIUS is equal to 77 FAHRENHEIT // You can also use the shortcut methods on the DTO echo $initialTemp->toF(); // Converts to Fahrenheit // Output: 77 FAHRENHEIT echo $initialTemp->toK(); // Converts to Kelvin // Output: 298.15 KELVIN
Available Temperature Units (TemperatureEnum
):
Enum Case | String Value |
---|---|
TemperatureEnum::CELSIUS |
'CELSIUS' |
TemperatureEnum::FAHRENHEIT |
'FAHRENHEIT' |
TemperatureEnum::KELVIN |
'KELVIN' |
Marketplace Unit Conversion Service
The Bramato\DimensionUtility\Domain\Services\MarketplaceUnitConversionService
provides static methods to easily convert dimension and weight values provided by different marketplaces (using their specific unit strings like 'inches', 'pounds') into the library's internal DimensionDto
and WeightDto
objects.
Usage
use Bramato\DimensionUtility\Domain\Services\MarketplaceUnitConversionService; use Bramato\DimensionUtility\Dto\DimensionDto; // Assuming this DTO exists use Bramato\DimensionUtility\Dto\WeightDto; // Assuming this DTO exists use Bramato\DimensionUtility\Enum\DimensionEnum; use Bramato\DimensionUtility\Enum\WeightEnum; // Example data from a marketplace (e.g., Amazon) $lengthValue = 15.5; $lengthUnit = 'inches'; // Common unit string from marketplace $weightValue = 2.1; $weightUnit = 'kilograms'; // Convert using the service (defaults to 'amazon' marketplace mapping) try { /** @var DimensionDto $dimension */ $dimension = MarketplaceUnitConversionService::createDimensionFromMarketplace($lengthValue, $lengthUnit); // $dimension->value will be 15.5 // $dimension->unit will be DimensionEnum::INCH /** @var WeightDto $weight */ $weight = MarketplaceUnitConversionService::createWeightFromMarketplace($weightValue, $weightUnit); // $weight->value will be 2.1 // $weight->unit will be WeightEnum::KILOGRAM // Generic conversion (determines if it's Dimension or Weight based on unit) $genericDto = MarketplaceUnitConversionService::createFromMarketplace(500, 'grams'); if ($genericDto instanceof WeightDto) { // It's a WeightDto(500, WeightEnum::GRAM) } } catch (\InvalidArgumentException $e) { // Handle cases where the unit or marketplace is unknown/invalid echo "Error: " . $e->getMessage(); }
Supported Marketplaces
Currently, the service explicitly supports mappings for:
amazon
(default)
Extending for Other Marketplaces
To add support for a new marketplace (e.g., 'ebay'):
- Add a new static array property in
MarketplaceUnitConversionService
with the specific unit mappings for that marketplace (e.g.,private static array $ebayUnitMappings = [...]
). - Update the
match
statement within thegetMappingForMarketplace
method to include a case for the new marketplace identifier (e.g.,'ebay' => self::$ebayUnitMappings,
). - You can then call the conversion methods specifying the new marketplace:
$ebayWeight = MarketplaceUnitConversionService::createWeightFromMarketplace(1500, 'g', 'ebay'); // Assuming 'g' maps to GRAM in ebayUnitMappings
Speed Conversion
<?php use Bramato\DimensionUtility\Dto\SpeedDto; use Bramato\DimensionUtility\Enum\SpeedEnum; use Bramato\DimensionUtility\Services\SpeedConversionService; // Create a SpeedDto $initialSpeed = new SpeedDto(100, SpeedEnum::KILOMETER_PER_HOUR); // Or using the static factory method // $initialSpeed = SpeedDto::create(100, 'KILOMETER_PER_HOUR'); // Get the conversion service $conversionService = SpeedConversionService::create($initialSpeed); // Convert to another unit $convertedSpeed = $conversionService->convert(SpeedEnum::MILE_PER_HOUR); echo $initialSpeed . " is equal to " . $convertedSpeed; // Output: 100 KILOMETER_PER_HOUR is equal to 62.1371 MILE_PER_HOUR (approx) // You can also use the shortcut methods on the DTO echo $initialSpeed->toMPS(); // Converts to Meters per Second // Output: 27.777... METER_PER_SECOND echo $initialSpeed->toMPH(); // Converts to Miles per Hour // Output: 62.1371 MILE_PER_HOUR (approx)
Available Speed Units (SpeedEnum
):
Enum Case | String Value |
---|---|
SpeedEnum::METER_PER_SECOND |
'METER_PER_SECOND' |
SpeedEnum::KILOMETER_PER_HOUR |
'KILOMETER_PER_HOUR' |
SpeedEnum::MILE_PER_HOUR |
'MILE_PER_HOUR' |
SpeedEnum::FOOT_PER_SECOND |
'FOOT_PER_SECOND' |
SpeedEnum::KNOT |
'KNOT' |
Data Storage Conversion
Note: This conversion service uses the BCMath PHP extension for arbitrary precision math, as data storage values can become very large. Ensure the bcmath
extension is enabled in your PHP environment.
<?php use Bramato\DimensionUtility\Dto\DataStorageDto; use Bramato\DimensionUtility\Enum\DataStorageEnum; use Bramato\DimensionUtility\Services\DataStorageConversionService; // Create a DataStorageDto $initialStorage = new DataStorageDto(512, DataStorageEnum::MEBIBYTE); // Or using the static factory method // $initialStorage = DataStorageDto::create(512, 'MEBIBYTE'); // Get the conversion service $conversionService = DataStorageConversionService::create($initialStorage); // Convert to another unit $convertedStorage = $conversionService->convert(DataStorageEnum::GIBIBYTE); echo $initialStorage . " is equal to " . $convertedStorage; // Output: 512 MEBIBYTE is equal to 0.5 GIBIBYTE // You can also use the shortcut methods on the DTO echo $initialStorage->toKiB(); // Converts to Kibibytes // Output: 524288 KIBIBYTE echo $initialStorage->toGiB(); // Converts to Gibibytes // Output: 0.5 GIBIBYTE
Available Data Storage Units (DataStorageEnum
- Binary Prefixes):
Enum Case | String Value |
---|---|
DataStorageEnum::BYTE |
'BYTE' |
DataStorageEnum::KIBIBYTE |
'KIBIBYTE' |
DataStorageEnum::MEBIBYTE |
'MEBIBYTE' |
DataStorageEnum::GIBIBYTE |
'GIBIBYTE' |
DataStorageEnum::TEBIBYTE |
'TEBIBYTE' |
DataStorageEnum::PEBIBYTE |
'PEBIBYTE' |
Pressure Conversion
<?php use Bramato\DimensionUtility\Dto\PressureDto; use Bramato\DimensionUtility\Enum\PressureEnum; use Bramato\DimensionUtility\Services\PressureConversionService; // Create a PressureDto $initialPressure = new PressureDto(1, PressureEnum::BAR); // Or using the static factory method // $initialPressure = PressureDto::create(1, 'BAR'); // Get the conversion service $conversionService = PressureConversionService::create($initialPressure); // Convert to another unit $convertedPressure = $conversionService->convert(PressureEnum::PSI); echo $initialPressure . " is equal to " . $convertedPressure; // Output: 1 BAR is equal to 14.50377 PSI (approx) // You can also use the shortcut methods on the DTO echo $initialPressure->toPa(); // Converts to Pascals // Output: 100000 PASCAL echo $initialPressure->toPsi(); // Converts to PSI // Output: 14.50377 PSI (approx)
Available Pressure Units (PressureEnum
):
Enum Case | String Value |
---|---|
PressureEnum::PASCAL |
'PASCAL' |
PressureEnum::KILOPASCAL |
'KILOPASCAL' |
PressureEnum::MEGAPASCAL |
'MEGAPASCAL' |
PressureEnum::BAR |
'BAR' |
PressureEnum::MILLIBAR |
'MILLIBAR' |
PressureEnum::PSI |
'PSI' |
PressureEnum::ATMOSPHERE |
'ATMOSPHERE' |
PressureEnum::TORR |
'TORR' |
Domain DTOs
In addition to the base DTOs for individual units, the package provides several "Domain DTOs" under the Bramato\DimensionUtility\Domain\Dto
namespace. These DTOs represent more complex real-world concepts and utilize the base DTOs for their measurements.
BoxDto(DimensionDto $length, DimensionDto $width, DimensionDto $height)
: Represents a physical box with dimensions.calculateVolume(): float
- Calculates volume in cubic meters.calculateSurfaceArea(): float
- Calculates surface area in square meters.getMaxDimension(?DimensionEnum $unitToReturn = null): DimensionDto
- Gets the largest dimension, optionally converting it.
ProductDto(string $sku, string $name, BoxDto $dimensions, WeightDto $weight, ?LiquidVolumeDto $liquidVolume = null)
: Represents a product with SKU, name, dimensions, weight, and optional liquid volume.createMetric(...)
: Static factory using CM and KG.createImperial(...)
: Static factory using INCH and POUND.
ProductPackageDto(ProductDto $product, BoxDto $packageDimensions, WeightDto $totalWeight, ?WeightDto $emptyPackageWeight = null)
: Represents a packaged product, including the product itself, package dimensions, total weight, and optional empty package weight.calculatePackagingWeight(?WeightEnum $unitToReturn = null): ?WeightDto
- Calculates the weight of the packaging.getPackagingWeight(?WeightEnum $unitToReturn = null): ?WeightDto
- Gets the provided or calculated packaging weight.
FileInfoDto(string $path, DataStorageDto $size, ?string $mimeType = null)
: Represents information about a file, including its path, size, and optional MIME type.getFilename(): string
- Extracts the filename from the path.getExtension(): ?string
- Extracts the file extension from the path.
LocationDto(float $latitude, float $longitude, ?DimensionDto $altitude = null)
: Represents geographical coordinates with optional altitude (as aDimensionDto
). Validates latitude (-90 to 90) and longitude (-180 to 180).FullfilledBoxDto(BoxDto $dimensions, WeightDto $totalWeight)
: Represents a box with dimensions and a total weight (box + contents).createMetric(...)
: Static factory using CM and KG.createImperial(...)
: Static factory using INCH and POUND.
PhysicalObjectTrait
: A trait providing common methods for physical objects (like calculating volume or density if dimensions and weight are present). Note: Currently defined but not used by the provided DTOs.WeatherReadingDto(...)
: Represents a weather reading with various measurements (temperature, pressure, etc.). Note: Currently defined but requires further implementation/usage examples.
Domain DTO Usage Examples
Creating Products using Factory Methods:
<?php use Bramato\DimensionUtility\Domain\Dto\ProductDto; // Create using metric units $productMetric = ProductDto::createMetric( sku: 'MTR001', name: 'Metric Widget', lengthCm: 25, widthCm: 15, heightCm: 10, weightKg: 0.8 ); echo "Created Metric Product: {$productMetric->name} ({$productMetric->weight})\n"; // Create using imperial units $productImperial = ProductDto::createImperial( sku: 'IMP001', name: 'Imperial Gadget', lengthInch: 10, widthInch: 6, heightInch: 4, weightPound: 1.75 ); echo "Created Imperial Product: {$productImperial->name} ({$productImperial->weight})\n";
Calculating Product Density:
<?php use Bramato\DimensionUtility\Domain\Dto\ProductDto; use Bramato\DimensionUtility\Domain\Dto\BoxDto; use Bramato\DimensionUtility\Dto\DimensionDto; use Bramato\DimensionUtility\Dto\WeightDto; use Bramato\DimensionUtility\Enum\DimensionEnum; use Bramato\DimensionUtility\Enum\WeightEnum; $dimensions = new BoxDto( new DimensionDto(10, DimensionEnum::CENTIMETER), new DimensionDto(20, DimensionEnum::CENTIMETER), new DimensionDto(5, DimensionEnum::CENTIMETER) // Volume = 0.001 m³ ); $weight = new WeightDto(500, WeightEnum::GRAM); // 0.5 kg $product = new ProductDto('PROD001', 'My Product', $dimensions, $weight); // ProductDto uses PhysicalObjectTrait try { $density = $product->calculateDensity(); // Returns density in kg/m³ echo "Product density: " . round($density, 2) . " kg/m³"; // Output: Product density: 500 kg/m³ } catch (\LogicException $e) { echo "Error calculating density: " . $e->getMessage(); }
Creating a Weather Reading:
<?php use Bramato\DimensionUtility\Domain\Dto\LocationDto; use Bramato\DimensionUtility\Domain\Dto\WeatherReadingDto; use Bramato\DimensionUtility\Dto\TemperatureDto; use Bramato\DimensionUtility\Dto\PressureDto; use Bramato\DimensionUtility\Dto\SpeedDto; use Bramato\DimensionUtility\Enum\TemperatureEnum; use Bramato\DimensionUtility\Enum\PressureEnum; use Bramato\DimensionUtility\Enum\SpeedEnum; use DateTimeImmutable; $timestamp = new DateTimeImmutable('2025-07-01 12:00:00'); $location = new LocationDto(latitude: 40.7128, longitude: -74.0060); // New York $temperature = new TemperatureDto(28, TemperatureEnum::CELSIUS); $pressure = new PressureDto(1010, PressureEnum::MILLIBAR); $humidity = 55.0; // Percentage $windSpeed = new SpeedDto(10, SpeedEnum::MILE_PER_HOUR); $windDirection = 180.0; // South $reading = new WeatherReadingDto( timestamp: $timestamp, location: $location, temperature: $temperature, pressure: $pressure, humidity: $humidity, windSpeed: $windSpeed, windDirection: $windDirection ); echo "Weather reading at {$reading->location->latitude}, {$reading->location->longitude} on {$reading->timestamp->format('Y-m-d H:i')}:\n"; echo "- Temperature: {$reading->temperature}\n"; echo "- Pressure: {$reading->pressure}\n"; echo "- Humidity: {$reading->humidity}%\n"; echo "- Wind: {$reading->windSpeed} from {$reading->windDirection} degrees\n";
Testing
This package uses Pest for unit testing. The suite currently includes 185 tests covering all DTOs, Enums, and Conversion Services. To run the tests, follow these steps:
- Ensure you have installed the development dependencies:
composer install
- Run the Pest test suite:
./vendor/bin/pest
Contributing
Contributions are welcome! Please feel free to submit a pull request.
License
The MIT License (MIT). Please see License File for more information. (Note: You might want to create a LICENSE.md file with the MIT license text).
Domain DTOs
This package also includes higher-level DTOs in the Bramato\DimensionUtility\Domain\Dto
namespace:
BoxDto
: Represents a physical box with external and internal dimensions, empty weight, and maximum weight capacity.ProductDto
: Represents a product with dimensions and weight.FullfilledBoxDto
: Represents a packed box, containing aBoxDto
(the box used), the total weight, and an array ofProductDto
items inside.
Domain Services
PacketBoxService
: A service utilizing thedvdoug/boxpacker
library to solve the bin packing problem. It takes availableBoxDto
definitions (with quantities) andProductDto
items (with quantities) and calculates how to pack the items into the boxes, returning an array ofFullfilledBoxDto
.
<?php use Bramato\DimensionUtility\Domain\Services\PacketBoxService; use Bramato\DimensionUtility\Domain\Dto\BoxDto; use Bramato\DimensionUtility\Domain\Dto\ProductDto; use Bramato\DimensionUtility\Dto\DimensionDto; use Bramato\DimensionUtility\Dto\WeightDto; use Bramato\DimensionUtility\Enum\DimensionEnum; use Bramato\DimensionUtility\Enum\WeightEnum; $packerService = new PacketBoxService(); // Add available box types $box1 = new BoxDto( new DimensionDto(30, DimensionEnum::CENTIMETER), new DimensionDto(20, DimensionEnum::CENTIMETER), new DimensionDto(10, DimensionEnum::CENTIMETER), new WeightDto(150, WeightEnum::GRAM), // Empty weight new WeightDto(5000, WeightEnum::GRAM) // Max weight ); $packerService->addBox($box1, 50); // 50 boxes of this type available // Add items to pack $product1 = ProductDto::createMetric(10, 8, 4, 250); // L, W, H in cm, Weight in g $product2 = ProductDto::createMetric(15, 10, 5, 600); $packerService->addItem($product1, false, 3); // Add 3 of product1 (not pre-packed) $packerService->addItem($product2, false, 2); // Add 2 of product2 (not pre-packed) // Perform packing $packedBoxesResult = $packerService->packItems(); foreach ($packedBoxesResult as $fulfilledBox) { echo "Packed Box: " . $fulfilledBox->dimensions->length . "x" . $fulfilledBox->dimensions->width . "x" . $fulfilledBox->dimensions->height . "\n"; echo "Total Weight: " . $fulfilledBox->totalWeight . "\n"; echo "Items: \n"; foreach ($fulfilledBox->items as $item) { echo " - Product: [" . $item->getDimensionsInCM()->length . "x" . $item->getDimensionsInCM()->width . "x" . $item->getDimensionsInCM()->height . ", " . $item->getWeightInG() . "g]\n"; } echo "-----\n"; }
Acknowledgements
The bin packing functionality provided by PacketBoxService
relies heavily on the excellent dvdoug/boxpacker library by Doug Wright. Thank you for providing such a useful tool to the PHP community!