teamchallengeapps / distance
PHP Distance (Value Object) Helper
Installs: 7 322
Dependents: 0
Suggesters: 0
Security: 0
Stars: 8
Watchers: 2
Forks: 5
Open Issues: 0
pkg:composer/teamchallengeapps/distance
Requires
- php: ^8.2
- ext-intl: *
- brick/math: ^0.12
- illuminate/support: ^10.0|^11.0|^12.0
- livewire/livewire: ^3.0
Requires (Dev)
- orchestra/testbench: ^8.26
- phpunit/phpunit: ^9.0
README
About
This Distance Helper package contains a tested PHP Value Object which makes working with, comparing, converting and formatting distances (inches, centimeters, meters, kilometers, miles and steps) easy and fluent.
The inspiration for the package came from PHP helpers like Carbon, and an effort to refactor the code behind the virtual workplace walking challenge system Big Team Challenge.
Installation
You can pull in this package through composer
composer require teamchallengeapps/distance
The package (particularly configuration) is designed to work with Laravel 10+ using autodiscovery. You can manually add our service provider within the providers array:
\TeamChallengeApps\Distance\DistanceServiceProvider::class,
Usage
To create a new distance you, simply new-up an instance of the Distance class.
use TeamChallengeApps\Distance\DistanceValue; use TeamChallengeApps\Distance\Unit; $meters = new DistanceValue(100, Unit::Meters); $km = new DistanceValue(10.5, Unit::Kilometers); $miles = new DistanceValue(10, Unit::Miles); $steps = new DistanceValue(10000, Unit::Footsteps);
The default (base) unit is centimeters, so ommitting the second (optional) constructor argument will default to meters. This is chosen to be the smallest (integer) measurement in your datastore - similar to storing integer cents rather than decimal dollars for money.
$centimeters = new DistanceValue(100);
API
Converting
You can convert a distance object to a new unit using the convertTo methods.
use TeamChallengeApps\Distance\DistanceValue; use TeamChallengeApps\Distance\Unit; $centimeters = new DistanceValue(1000, Unit::Centimeters); $meters = $centimeters->convertTo(Unit::Meters); echo $meters->getValue(); // 1
If you want to convert to the base unit (centimeters by default), you can do:
$distance->convertToBase();
The conversions are stored inside the distance.conversions config in the format, e.g:
'conversions' => [
'centimeters:meters' => 0.01,
...
]
Comparison
Empty / zero
use TeamChallengeApps\Distance\DistanceValue; $distance new DistanceValue(0); // or $distance = DistanceValue::zero(); if ($distance->isZero()) { }
Positive / negative
use TeamChallengeApps\Distance\DistanceValue; $distance new DistanceValue(100); $distance->isPositive(); // true $distance->isNegative(); // false
Value Comparison
You can compare two distances, but you will get a ComparisonException exception if the units do not match
use TeamChallengeApps\Distance\DistanceValue; $distance = new DistanceValue(10); $total = new DistanceValue(100); if ($distance->equals($total) ) { // Equal to } if ($distance->lessThan($total) || $distance->lt($total)) { // Less than || alias } if ($distance->lessThanOrEqual($total) || $distance->lte($total)) { // Less than or equal || alias } if ($distance->greaterThan($total) || $distance->gt($total)) { // Greater than || alias } if ($distance->greaterThanOrEqual($total) || $distance->gte($total)) { // Greater than or equal || alias }
Calculations
Percentage
use TeamChallengeApps\Distance\DistanceValue; $distance = new DistanceValue(10); $total = new DistanceValue(100); $percentage = $distance->percentageOf($total); // 10
By default, the real percentage returned, but passing false as the second parameter will cap at 100.
use TeamChallengeApps\Distance\DistanceValue; $distance = new DistanceValue(150); $total = new DistanceValue(100); $percentage = $distance->percentageOf($total); // 150 $percentage = $distance->percentageOf(distance: $total, overflow: false); // 100
Add
use TeamChallengeApps\Distance\DistanceValue; $total = new DistanceValue(1000); $logged = new DistanceValue(10); $result = $total->add($logged); echo $result->getValue(); // 1010
Subtract
$total = new DistanceValue(1010); $redeemed = new DistanceValue(10); $result = $total->subtract($logged); echo $result->getValue(); // 1000
Multiply
use TeamChallengeApps\Distance\DistanceValue; $value = new DistanceValue(5); $result = $total->multiply(3); echo $result->getValue(); // 15
Divide
use TeamChallengeApps\Distance\DistanceValue; $value = new DistanceValue(15); $result = $total->divide(3); echo $result->getValue(); // 5
Formatting
String
Using PHP's magic __toString() method, echo-ing or casting the object itself will round and use php-intl's NumberFormatter to render as a string.
use TeamChallengeApps\Distance\DistanceValue; $distance = new DistanceValue(100500.591); echo $distance; // 100,500.59 centimeters $value = (string) $distance; echo $value; // "100,500.59 centimeters"
You can change the default precision (2) and rounding mode for each unit in the config file:
php artisan vendor:publish --provider="TeamChallengeApps\Distance\DistanceServiceProvider" --tag="config"
return [ 'formatting' => [ 'precision' => [ 'footsteps' => 0, 'inches' => 0, ], 'translation' => [ /* Set if you wish to use Laravel pluralization of unit strings */ 'choice' => true, ], 'round' => [ 'footsteps' => \TeamChallengeApps\Distance\RoundingMode::CEILING, ], ] ];
You can also pass options each time you use format:
use TeamChallengeApps\Distance\DistanceValue; use TeamChallengeApps\Distance\Unit; $meters = new DistanceValue(1.00005, Unit::Meters); /** Default - auto converted to centimeters (default display) and rounded to 2 decimal places */ echo $meters->format(); // 100.01 centimeters /** Not converted from original unit but still rounded and using singular suffix */ echo $meters->format(convert: false); // 1 meter /** Not converted from original unit but still rounded and using singular translated suffix */ echo $meters->format(convert: false, options: ['precision' => 4, 'unit' => false]); // 1.0001
Abbreviated
There is also an abbreviated string helper for steps:
use TeamChallengeApps\Distance\DistanceValue; use TeamChallengeApps\Distance\Unit; $steps = new DistanceValue(124000, Unit::Footsteps); echo $steps->formatUsing(formatter: "abbreviated", convert: false); // 124k steps
Decimal
use TeamChallengeApps\Distance\DistanceValue; use TeamChallengeApps\Distance\Unit; $distance = new DistanceValue(100, Unit::Meters); echo $distance->formatDecimal(convert: false)); // 100.0 $distance = new DistanceValue(100.56678, Unit::Meters); echo $distance->formatDecimal(convert: false)); // 100.57 $distance = new DistanceValue(100.56678, Unit::Meters); echo $distance->formatDecimal(convert: false, options: ['precision' => 3])); // 100.567
Contributing
Please submit improvements and fixes :)
Changelog
Look at the CHANGELOG.md for this package.