Skip to content

Commit 1edb134

Browse files
committed
Refactor normalization
1 parent d0f25e9 commit 1edb134

5 files changed

Lines changed: 48 additions & 25 deletions

File tree

src/Doctrine/DBAL/Types/DurationType.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public function convertToPHPValue($value, AbstractPlatform $platform): ?Duration
3232
*/
3333
$databaseUnit = new static::$databaseUnitClass($value);
3434

35-
return new Duration($databaseUnit->normalize());
35+
return new Duration($databaseUnit);
3636
}
3737

3838
public function convertToDatabaseValue($value, AbstractPlatform $platform): ?string

src/Form/DistanceType.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ function (?Distance $data): ?array {
3333
return null;
3434
}
3535

36-
$value = $data->getValue();
36+
$value = $data->getValue()->normalize();
3737

3838
return [
3939
'value' => (string) $value->getValue(),

src/Model/AbstractUnit.php

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -209,27 +209,48 @@ public function convert(string $targetUnitClassOrType): UnitInterface
209209
public function normalize(): UnitInterface
210210
{
211211
$mapping = static::getMapping();
212-
$sourceUnitClass = $mapping[static::getUnitType()] ?? null;
213212

214-
if (null === $sourceUnitClass) {
215-
throw new \InvalidArgumentException(\sprintf("Normalization from '%s' is not supported.", static::class));
213+
if (0 === $this->value->compare(new Number(0))) {
214+
return new static(0);
216215
}
217216

218-
$shortest = $this;
217+
$candidates = [];
219218

220-
foreach ($mapping as $targetUnitClass) {
221-
if (static::class === $targetUnitClass) {
222-
continue;
219+
foreach ($mapping as $unitClass) {
220+
$converted = $this->convert($unitClass);
221+
$absValue = abs((float) $converted->getValue()->value);
222+
223+
// Collect candidates where the number is at least 1.
224+
if ($absValue >= 1) {
225+
$candidates[] = [
226+
'unit' => $converted,
227+
'value' => $absValue,
228+
];
223229
}
230+
}
231+
232+
// >= 1
233+
if (0 !== \count($candidates)) {
234+
usort($candidates, static function ($a, $b) {
235+
return $a['value'] <=> $b['value'];
236+
});
237+
238+
return $candidates[0]['unit'];
239+
}
240+
241+
// < 1
242+
$bestCandidate = null;
224243

225-
$converted = $this->convert($targetUnitClass);
244+
foreach ($mapping as $unitClass) {
245+
$converted = $this->convert($unitClass);
246+
$absValue = abs((float) $converted->getValue()->value);
226247

227-
if (\strlen($converted->format()) < \strlen($shortest->format())) {
228-
$shortest = $converted;
248+
if (null === $bestCandidate || $absValue > $bestCandidate['value']) {
249+
$bestCandidate = ['unit' => $converted, 'value' => $absValue];
229250
}
230251
}
231252

232-
return $shortest;
253+
return $bestCandidate['unit'] ?? $this;
233254
}
234255

235256
public static function create(Number|string|int|float $value, string $unitType): static

tests/Doctrine/TypesTest.php

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -58,23 +58,23 @@ public static function distanceTypeDataProvider(): array
5858
['0.0', '0m'],
5959
['1.0', '1m'],
6060
['-1.0', '-1m'],
61-
['123.456', '123.456m'],
62-
['-987.654', '-987.654m'],
61+
['123.456', '1.23456hm'],
62+
['-987.654', '-9.87654hm'],
6363
['0.00001', '10μm'],
6464
['-0.00001', '-10μm'],
6565
['1.23456789', '1.23456789m'],
66-
['999999.9999', '999999.9999m'],
67-
['-999999.9999', '-999999.9999m'],
66+
['999999.9999', '999.9999999km'],
67+
['-999999.9999', '-999.9999999km'],
6868
['3.1415926535', '3.1415926535m'],
6969
['2.7182818284', '2.7182818284m'],
70-
['123456789.123', '123456789.123m'],
70+
['123456789.123', '123456.789123km'],
7171

7272
['0', '0m'],
73-
['+123.45', '123.45m'],
73+
['+123.45', '1.2345hm'],
7474
['-0.0', '0m'],
7575
['0001.000', '1m'],
76-
['123.', '123m'],
77-
['.456', '456mm'],
76+
['123.', '1.23hm'],
77+
['.456', '4.56dm'],
7878
['0.000000001', '1nm'],
7979
['1e-5', '10μm'],
8080
['1e5', '100km'],

tests/Form/DistanceTypeTest.php

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace Form;
44

55
use SoureCode\Bundle\Unit\Form\DistanceType;
6+
use SoureCode\Bundle\Unit\Model\Distance;
67
use SoureCode\Bundle\Unit\Model\Length\Centimeter;
78
use SoureCode\Bundle\Unit\Model\Length\Kilometer;
89
use SoureCode\Bundle\Unit\Model\Length\LengthUnitType;
@@ -23,7 +24,7 @@ public function testSubmitValidData(): void
2324

2425
// Assert
2526
$this->assertTrue($form->isSynchronized());
26-
$this->assertEquals('106mm', $form->getData()->format());
27+
$this->assertEquals('1.06dm', $form->getData()->format());
2728
}
2829

2930
public function testSubmitNull(): void
@@ -42,14 +43,15 @@ public function testSubmitNull(): void
4243
public function testWithPreData(): void
4344
{
4445
// Arrange
45-
$form = $this->factory->create(DistanceType::class, new Centimeter("10.6"));
46+
$distance = new Distance(new Centimeter("10.6"));
47+
$form = $this->factory->create(DistanceType::class, $distance);
4648

4749
// Act
4850
$view = $form->createView();
4951

5052
// Assert
51-
$this->assertEquals('10.6', $view->children['value']->vars['value']);
52-
$this->assertEquals(LengthUnitType::CENTIMETER->value, $view->children['unit']->vars['value']);
53+
$this->assertEquals('1.06', $view->children['value']->vars['value']);
54+
$this->assertEquals(LengthUnitType::DECIMETER->value, $view->children['unit']->vars['value']);
5355
}
5456

5557
public function testWithNullPreData(): void

0 commit comments

Comments
 (0)