Skip to main content

UnitTypeUseDefaultValueException

Thrown when attempting to create a unit with value = 1 when a base unit already exists for that type.

Namespace​

JobMetric\UnitConverter\Exceptions\UnitTypeUseDefaultValueException

HTTP Status Code​

400 Bad Request

Constructor​

public function __construct(
string $type,
int $code = 400,
?Throwable $previous = null
)

Parameters​

ParameterTypeDescription
$typestringThe unit type where a base unit already exists
$codeintHTTP status code (default: 400)
$previousThrowable|nullPrevious exception for chaining

Understanding the Rule​

In Laravel Unit Converter's base unit system:

  1. Each type can have only one base unit with value = 1
  2. The base unit serves as the reference point for all conversions
  3. Having multiple base units would break the conversion mathematics

Why Only One Base Unit?​

The conversion formula relies on a single reference:

result = input_value × (from_unit.value / to_unit.value)

If two units had value = 1, they would be mathematically equivalent, causing confusion and potential data integrity issues.

When Is It Thrown?​

This exception is thrown when you try to create a unit with value = 1 for a type that already has a base unit.

Example: Duplicate Base Unit Attempt​

use JobMetric\UnitConverter\Facades\UnitConverter;

// Gram already exists as the base unit for weight (value = 1)

// Trying to create another unit with value = 1 - WRONG!
UnitConverter::store([
'type' => 'weight',
'value' => 1, // Error! Base unit already exists
'translation' => [
'en' => ['name' => 'Base Weight', 'code' => 'bw'],
],
]);
// Throws: UnitTypeUseDefaultValueException

Correct Approach​

use JobMetric\UnitConverter\Facades\UnitConverter;

// Gram (base unit) already exists

// Create new unit with value relative to gram
UnitConverter::store([
'type' => 'weight',
'value' => 1000, // Not 1, relative to gram
'translation' => [
'en' => ['name' => 'Kilogram', 'code' => 'kg'],
],
]);
// Success!

Handling the Exception​

In Controllers​

use JobMetric\UnitConverter\Exceptions\UnitTypeUseDefaultValueException;
use JobMetric\UnitConverter\Facades\UnitConverter;

class UnitController extends Controller
{
public function store(Request $request)
{
try {
$response = UnitConverter::store($request->all());
return response()->json($response->data, 201);
} catch (UnitTypeUseDefaultValueException $e) {
return response()->json([
'error' => 'base_unit_exists',
'message' => $e->getMessage(),
'hint' => 'A base unit (value = 1) already exists for this type. Use a different value.',
], 400);
}
}
}

In Form Validation​

Prevent the issue before it reaches the service:

use JobMetric\UnitConverter\Models\Unit;

class StoreUnitRequest extends FormRequest
{
public function rules(): array
{
return [
'type' => 'required|string',
'value' => 'required|numeric|min:0',
'translation' => 'required|array',
];
}

public function withValidator($validator): void
{
$validator->after(function ($validator) {
$type = $this->input('type');
$value = (float) $this->input('value');

if ($value === 1.0) {
$baseExists = Unit::where('type', $type)
->where('value', 1)
->exists();

if ($baseExists) {
$validator->errors()->add(
'value',
"A base unit (value = 1) already exists for type '{$type}'"
);
}
}
});
}
}

Prevention​

1. Check Before Creating​

use JobMetric\UnitConverter\Models\Unit;
use JobMetric\UnitConverter\Facades\UnitConverter;

function createUnitSafely(array $data): mixed
{
$type = $data['type'];
$value = (float) $data['value'];

if ($value === 1.0) {
$baseExists = Unit::where('type', $type)->where('value', 1)->exists();

if ($baseExists) {
throw new \InvalidArgumentException(
"Base unit already exists for type '{$type}'. Use changeDefaultValue() to change the base unit."
);
}
}

return UnitConverter::store($data);
}

2. Use changeDefaultValue() Instead​

If you want to change which unit is the base unit, use changeDefaultValue():

use JobMetric\UnitConverter\Facades\UnitConverter;

// Current state:
// - Gram: value = 1 (base)
// - Kilogram: value = 1000

// Make Kilogram the new base unit
UnitConverter::changeDefaultValue($kilogramId);

// New state:
// - Gram: value = 0.001
// - Kilogram: value = 1 (new base)

3. UI Validation​

In your frontend, prevent users from entering value = 1 if a base unit exists:

// Example Vue.js validation
async function validateUnitValue(type, value) {
if (value === 1) {
const response = await fetch(`/api/units/base-exists/${type}`);
const { exists } = await response.json();

if (exists) {
return 'A base unit already exists for this type';
}
}
return null;
}

What If You Need to Change the Base Unit?​

Use the changeDefaultValue() method to designate a different unit as the base:

use JobMetric\UnitConverter\Facades\UnitConverter;

// Scenario: You want Kilogram to be the base unit instead of Gram

// Find the kilogram unit
$kilogram = UnitConverter::findUnitByCode('kg');

// Make it the base unit
$response = UnitConverter::changeDefaultValue($kilogram->id);

if ($response->ok) {
// All other units in the type are automatically recalculated
// Kilogram: value = 1 (new base)
// Gram: value = 0.001 (was 1, now relative to kg)
// Ton: value = 1000 (was 1000000, now relative to kg)
}