174 lines
4.4 KiB
PHP
174 lines
4.4 KiB
PHP
<?php
|
|
|
|
namespace App\Helpers;
|
|
|
|
class UnitConverter
|
|
{
|
|
// Base units untuk konversi
|
|
const BASE_UNITS = [
|
|
'weight' => 'g', // gram sebagai base unit untuk berat
|
|
'volume' => 'ml', // mililiter sebagai base unit untuk volume
|
|
'quantity' => 'pcs' // pieces sebagai base unit untuk jumlah
|
|
];
|
|
|
|
// Mapping unit ke kategori
|
|
const UNIT_CATEGORIES = [
|
|
'g' => 'weight',
|
|
'kg' => 'weight',
|
|
'ml' => 'volume',
|
|
'l' => 'volume',
|
|
'pcs' => 'quantity'
|
|
];
|
|
|
|
// Konversi rate ke base unit
|
|
const CONVERSION_RATES = [
|
|
'g' => 1, // 1 gram = 1 gram (base)
|
|
'kg' => 1000, // 1 kg = 1000 gram
|
|
'ml' => 1, // 1 ml = 1 ml (base)
|
|
'l' => 1000, // 1 liter = 1000 ml
|
|
'pcs' => 1 // 1 pcs = 1 pcs (base)
|
|
];
|
|
|
|
const UNIT_LABELS = [
|
|
'g' => 'Gram',
|
|
'kg' => 'Kilogram',
|
|
'ml' => 'Mililiter',
|
|
'l' => 'Liter',
|
|
'pcs' => 'Pieces'
|
|
];
|
|
|
|
/**
|
|
* Convert value from one unit to another
|
|
*/
|
|
public static function convert($value, $fromUnit, $toUnit)
|
|
{
|
|
// Check if units are in the same category
|
|
if (!self::areUnitsCompatible($fromUnit, $toUnit)) {
|
|
throw new \InvalidArgumentException("Cannot convert between {$fromUnit} and {$toUnit} - different categories");
|
|
}
|
|
|
|
// If same unit, return as is
|
|
if ($fromUnit === $toUnit) {
|
|
return $value;
|
|
}
|
|
|
|
// Convert to base unit first, then to target unit
|
|
$baseValue = $value * self::CONVERSION_RATES[$fromUnit];
|
|
$convertedValue = $baseValue / self::CONVERSION_RATES[$toUnit];
|
|
|
|
return round($convertedValue, 3); // Round to 3 decimal places
|
|
}
|
|
|
|
/**
|
|
* Convert value to base unit
|
|
*/
|
|
public static function toBaseUnit($value, $unit)
|
|
{
|
|
return $value * self::CONVERSION_RATES[$unit];
|
|
}
|
|
|
|
/**
|
|
* Convert value from base unit
|
|
*/
|
|
public static function fromBaseUnit($value, $unit)
|
|
{
|
|
return $value / self::CONVERSION_RATES[$unit];
|
|
}
|
|
|
|
/**
|
|
* Check if two units are compatible (same category)
|
|
*/
|
|
public static function areUnitsCompatible($unit1, $unit2)
|
|
{
|
|
if (!isset(self::UNIT_CATEGORIES[$unit1]) || !isset(self::UNIT_CATEGORIES[$unit2])) {
|
|
return false;
|
|
}
|
|
|
|
return self::UNIT_CATEGORIES[$unit1] === self::UNIT_CATEGORIES[$unit2];
|
|
}
|
|
|
|
/**
|
|
* Get unit category
|
|
*/
|
|
public static function getUnitCategory($unit)
|
|
{
|
|
return self::UNIT_CATEGORIES[$unit] ?? null;
|
|
}
|
|
|
|
/**
|
|
* Get base unit for a category
|
|
*/
|
|
public static function getBaseUnit($category)
|
|
{
|
|
return self::BASE_UNITS[$category] ?? null;
|
|
}
|
|
|
|
/**
|
|
* Get all available units
|
|
*/
|
|
public static function getAllUnits()
|
|
{
|
|
return array_keys(self::CONVERSION_RATES);
|
|
}
|
|
|
|
/**
|
|
* Get units by category
|
|
*/
|
|
public static function getUnitsByCategory($category)
|
|
{
|
|
$units = [];
|
|
foreach (self::UNIT_CATEGORIES as $unit => $cat) {
|
|
if ($cat === $category) {
|
|
$units[] = $unit;
|
|
}
|
|
}
|
|
return $units;
|
|
}
|
|
|
|
/**
|
|
* Get unit label
|
|
*/
|
|
public static function getUnitLabel($unit)
|
|
{
|
|
return self::UNIT_LABELS[$unit] ?? $unit;
|
|
}
|
|
|
|
/**
|
|
* Format value with unit
|
|
*/
|
|
public static function formatValue($value, $unit)
|
|
{
|
|
return number_format($value, 3) . ' ' . self::getUnitLabel($unit);
|
|
}
|
|
|
|
/**
|
|
* Get recommended unit for display (convert small values to appropriate unit)
|
|
*/
|
|
public static function getRecommendedDisplayUnit($value, $currentUnit)
|
|
{
|
|
$category = self::getUnitCategory($currentUnit);
|
|
|
|
if ($category === 'weight') {
|
|
// If value is >= 1000g, recommend kg
|
|
if ($value >= 1000 && $currentUnit === 'g') {
|
|
return 'kg';
|
|
}
|
|
// If value is < 1 kg, recommend g
|
|
if ($value < 1 && $currentUnit === 'kg') {
|
|
return 'g';
|
|
}
|
|
} elseif ($category === 'volume') {
|
|
// If value is >= 1000ml, recommend l
|
|
if ($value >= 1000 && $currentUnit === 'ml') {
|
|
return 'l';
|
|
}
|
|
// If value is < 1 l, recommend ml
|
|
if ($value < 1 && $currentUnit === 'l') {
|
|
return 'ml';
|
|
}
|
|
}
|
|
|
|
return $currentUnit;
|
|
}
|
|
}
|