diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
new file mode 100644
index 0000000..73faf98
--- /dev/null
+++ b/.github/workflows/tests.yml
@@ -0,0 +1,83 @@
+name: Tests
+on: push
+
+jobs:
+ build-84:
+ name: Static analysis, unit tests, and linting on PHP 8.4
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v6
+
+ - name: Setup PHP 8.4
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: '8.4'
+ tools: composer
+
+ - name: Cache Composer dependencies
+ uses: actions/cache@v5
+ with:
+ path: ./vendor
+ key: composer-${{ runner.os }}-8.4
+
+ - name: Install dependencies
+ run: |
+ composer install
+
+ - name: Run PHPStan
+ run: |
+ ./vendor/bin/phpstan
+
+ - name: PHP Code Sniffer
+ run: |
+ ./vendor/bin/phpcs
+
+ - name: Run PHPUnit
+ run: |
+ ./vendor/bin/phpunit
+
+ build-85:
+ name: Static analysis, unit tests, and linting on PHP 8.5
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v6
+
+ - name: Setup PHP 8.5
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: '8.5'
+ tools: composer
+ coverage: pcov
+
+ - name: Cache Composer dependencies
+ uses: actions/cache@v5
+ with:
+ path: ./vendor
+ key: composer-${{ runner.os }}-8.5
+
+ - name: Install dependencies
+ run: |
+ composer install
+
+ - name: Run PHPStan
+ run: |
+ ./vendor/bin/phpstan
+
+ - name: PHP Code Sniffer
+ run: |
+ ./vendor/bin/phpcs
+
+ - name: Run PHPUnit
+ run: |
+ ./vendor/bin/phpunit --coverage-clover ./coverage.xml
+
+ - name: Upload to Codecov
+ uses: codecov/codecov-action@v5
+ with:
+ token: ${{ secrets.CODECOV_TOKEN }}
+ files: ./coverage.xml
+ verbose: true
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 9e270ad..0f0f75e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,6 @@
+.idea
composer.phar
composer.lock
-vendor/
\ No newline at end of file
+vendor/
+.phpunit.cache
+.phpunit.result.cache
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index deb51d8..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,17 +0,0 @@
-language: php
-
-php:
- - 5.5
- - 5.6
- - 7.0
- - hhvm
-
-matrix:
- allow_failures:
- - php: 7.0
-
-sudo: false
-
-install: travis_retry composer install --no-interaction --prefer-source
-
-script: vendor/bin/phpunit
\ No newline at end of file
diff --git a/README.md b/README.md
index a3877bf..b9b96ec 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
# Distance
-[](https://travis-ci.org/ldebrouwer/distance)
+[](https://github.com/ldebrouwer/distance/actions/workflows/tests.yml)
[](https://packagist.org/packages/ldebrouwer/distance)
[](https://packagist.org/packages/ldebrouwer/distance)
[](https://packagist.org/packages/ldebrouwer/distance)
@@ -16,15 +16,20 @@ When using [Composer](https://getcomposer.org) you can always load in the latest
```bash
{
"require": {
- "ldebrouwer/distance": "~0.2"
+ "ldebrouwer/distance": "^1.0"
}
}
```
Check it out [on Packagist](https://packagist.org/packages/ldebrouwer/distance).
-## Documentation
+## Usage
-This is still on the to-do list. The code is pretty well documented though and should autocomplete in most IDEs.
+```php
+$distance = new Distance()
+ ->setFormula(Formula::HAVERSINE)
+ ->setUnit(Unit::KILOMETRES)
+ ->between(37.331741, -122.030333, 37.422546, -122.084250);
+```
## Still to come
- Expanded unit support.
diff --git a/composer.json b/composer.json
index 02b010b..13af2b5 100644
--- a/composer.json
+++ b/composer.json
@@ -17,15 +17,20 @@
{
"name": "Luc De Brouwer",
"email": "info@lucdebrouwer.nl",
- "homepage": "http://www.lucdebrouwer.nl",
- "role": "Developer"
+ "homepage": "http://www.lucdebrouwer.nl"
}
],
"require": {
- "php": ">=5.5"
+ "php": ">=8.4"
},
"require-dev": {
- "phpunit/phpunit": "4.6.*"
+ "phpunit/phpunit": "^13.0",
+ "phpstan/phpstan": "^2.1",
+ "phpstan/phpstan-phpunit": "^2.0",
+ "roave/security-advisories": "dev-latest",
+ "phpstan/phpstan-strict-rules": "^2.0",
+ "squizlabs/php_codesniffer": "^4.0",
+ "slevomat/coding-standard": "^8.27"
},
"extra": {
"branch-alias": {
@@ -33,6 +38,18 @@
}
},
"autoload": {
- "psr-4": {"LucDeBrouwer\\Distance\\": "src/"}
+ "psr-4": {
+ "ldebrouwer\\Distance\\": "src/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Tests\\ldebrouwer\\Distance\\": "tests/"
+ }
+ },
+ "config": {
+ "allow-plugins": {
+ "dealerdirect/phpcodesniffer-composer-installer": true
+ }
}
-}
\ No newline at end of file
+}
diff --git a/phpcs.xml b/phpcs.xml
new file mode 100644
index 0000000..d2e5a58
--- /dev/null
+++ b/phpcs.xml
@@ -0,0 +1,132 @@
+
+
+ The coding standard for ldebrouwer/distance.
+
+
+
+ src/
+ tests
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/phpstan.neon b/phpstan.neon
new file mode 100644
index 0000000..fa81b49
--- /dev/null
+++ b/phpstan.neon
@@ -0,0 +1,11 @@
+parameters:
+ level: max
+ paths:
+ - src
+ - tests
+ reportUnmatchedIgnoredErrors: true
+
+includes:
+ - vendor/phpstan/phpstan-phpunit/extension.neon
+ - vendor/phpstan/phpstan-strict-rules/rules.neon
+ - vendor/phpstan/phpstan/conf/bleedingEdge.neon
diff --git a/phpunit.xml b/phpunit.xml
index 6df70d2..a3722f2 100644
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -1,18 +1,23 @@
-
+ cacheDirectory=".phpunit.cache"
+ executionOrder="depends,defects"
+ beStrictAboutOutputDuringTests="true"
+ displayDetailsOnPhpunitDeprecations="true"
+ failOnPhpunitDeprecation="true"
+ failOnRisky="true"
+ failOnWarning="true">
-
- ./tests/
+
+ tests
-
\ No newline at end of file
+
+
+
+ src
+
+
+
diff --git a/src/Distance.php b/src/Distance.php
index d0eb5c2..0212b4c 100644
--- a/src/Distance.php
+++ b/src/Distance.php
@@ -1,87 +1,48 @@
- '100', // centimeters
- 'in' => '39.3700787', // inches
- 'ft' => '3.2808399', // feet
- 'm' => '1', // meters
- 'km' => '0.001', // kilometers
- 'mi' => '0.000621371192', // miles
- ];
+ private Unit $unit = Unit::KILOMETRES;
/**
- * Method that returns the distance between two GPS locations in the preferred unit according to the set formula.
- *
- * @param float $latitudeA The latitude for point A.
- * @param float $longitudeA The longitude for point A.
- * @param float $latitudeB The latitude for point B.
- * @param float $longitudeB The longitude for point B.
- *
- * @uses betweenVincenty
- * @uses betweenHaversine
- * @throws Exception
- * @return float
+ * Returns the distance between two GPS locations in the preferred unit according to the set formula.
*/
- public function between($latitudeA, $longitudeA, $latitudeB, $longitudeB)
+ public function between(float $latitudeA, float $longitudeA, float $latitudeB, float $longitudeB): float
{
- if (!floatval($latitudeA) || !floatval($longitudeA) || !floatval($latitudeB) || !floatval($longitudeB)) {
- throw new Exception('One or more of the parsed variables are not valid floats.');
- }
-
- $distanceInMeters = call_user_func_array([$this, 'between' . ucfirst($this->getFormula())],
- [$latitudeA, $longitudeA, $latitudeB, $longitudeB]);
+ $distanceInMeters = match ($this->formula) {
+ Formula::VINCENTY => $this->betweenVincenty($latitudeA, $longitudeA, $latitudeB, $longitudeB),
+ Formula::HAVERSINE => $this->betweenHaversine($latitudeA, $longitudeA, $latitudeB, $longitudeB),
+ };
return $this->convert($distanceInMeters);
}
/**
- * Method that returns the distance between two GPS locations in meters according to the Vincenty formula.
- *
- * @param float $latitudeA The latitude for point A.
- * @param float $longitudeA The longitude for point A.
- * @param float $latitudeB The latitude for point B.
- * @param float $longitudeB The longitude for point B.
- *
- * @return float
+ * Returns the distance between two GPS locations in meters according to the Vincenty formula.
*/
- private function betweenVincenty($latitudeA, $longitudeA, $latitudeB, $longitudeB)
+ private function betweenVincenty(float $latitudeA, float $longitudeA, float $latitudeB, float $longitudeB): float
{
$latitudeA = deg2rad($latitudeA);
$longitudeA = deg2rad($longitudeA);
$latitudeB = deg2rad($latitudeB);
$longitudeB = deg2rad($longitudeB);
$longDelta = $longitudeB - $longitudeA;
- $a = pow(cos($latitudeB) * sin($longDelta),
- 2) + pow(cos($latitudeA) * sin($latitudeB) - sin($latitudeA) * cos($latitudeB) * cos($longDelta), 2);
+ $a = ((cos($latitudeB) * sin($longDelta)) ** 2) + ((cos($latitudeA) * sin($latitudeB) - sin($latitudeA) * cos($latitudeB) * cos($longDelta)) ** 2);
$b = sin($latitudeA) * sin($latitudeB) + cos($latitudeA) * cos($latitudeB) * cos($longDelta);
$angle = atan2(sqrt($a), $b);
@@ -89,16 +50,9 @@ private function betweenVincenty($latitudeA, $longitudeA, $latitudeB, $longitude
}
/**
- * Method that returns the distance between two GPS locations in meters according to the Haversine formula.
- *
- * @param float $latitudeA The latitude for point A.
- * @param float $longitudeA The longitude for point A.
- * @param float $latitudeB The latitude for point B.
- * @param float $longitudeB The longitude for point B.
- *
- * @return float
+ * Returns the distance between two GPS locations in meters according to the Haversine formula.
*/
- private function betweenHaversine($latitudeA, $longitudeA, $latitudeB, $longitudeB)
+ private function betweenHaversine(float $latitudeA, float $longitudeA, float $latitudeB, float $longitudeB): float
{
$latitudeA = deg2rad($latitudeA);
$longitudeA = deg2rad($longitudeA);
@@ -106,80 +60,33 @@ private function betweenHaversine($latitudeA, $longitudeA, $latitudeB, $longitud
$longitudeB = deg2rad($longitudeB);
$latDelta = $latitudeB - $latitudeA;
$longDelta = $longitudeB - $longitudeA;
- $angle = 2 * asin(sqrt(pow(sin($latDelta / 2), 2) + cos($latitudeA) * cos($latitudeB) * pow(sin($longDelta / 2), 2)));
+ $angle = 2 * asin(sqrt((sin($latDelta / 2) ** 2) + cos($latitudeA) * cos($latitudeB) * (sin($longDelta / 2) ** 2)));
return floor($angle * 6371000);
}
- /**
- * @param $distance
- * @return mixed
- */
- private function convert($distance)
- {
- return $distance * $this->getConversion()[$this->getUnit()];
- }
-
- /**
- * Returns the currently set formula used for distance calculation.
- *
- * @return string
- */
- public function getFormula()
+ private function convert(float $distance): float
{
- return $this->formula;
+ return $distance * $this->unit->multiplierFromMetres();
}
/**
* Sets the formula to be used for distance calculation.
- *
- * @param string $formula
- *
- * @throws Exception
*/
- public function setFormula($formula)
+ public function setFormula(Formula $formula): self
{
- if (!in_array($formula, ['vincenty', 'haversine'])) {
- throw new Exception('You have tried to set an invalid distance formula.');
- }
-
$this->formula = $formula;
- }
- /**
- * Returns the currently set unit used when returning the distance between two coordinates.
- *
- * @return string
- */
- public function getUnit()
- {
- return $this->unit;
+ return $this;
}
/**
* Sets the unit to be used when returning the distance between two coordinates.
- *
- * @param string $unit
- *
- * @throws Exception
*/
- public function setUnit($unit)
+ public function setUnit(Unit $unit): self
{
- if (!in_array($unit, array_keys($this->getConversion()))) {
- throw new Exception('You have tried to set an invalid distance unit.');
- }
-
$this->unit = $unit;
- }
- /**
- * Gets the conversion table between different units.
- *
- * @return array
- */
- public function getConversion()
- {
- return $this->conversion;
+ return $this;
}
-
-}
\ No newline at end of file
+}
diff --git a/src/Formula.php b/src/Formula.php
new file mode 100644
index 0000000..156b079
--- /dev/null
+++ b/src/Formula.php
@@ -0,0 +1,11 @@
+ 100,
+ self::INCHES => 39.3700787,
+ self::FEET => 3.2808399,
+ self::METRES => 1,
+ self::KILOMETRES => 0.001,
+ self::MILES => 0.000621371192,
+ };
+ }
+}
diff --git a/tests/DistanceTest.php b/tests/DistanceTest.php
index e05abdd..f01e3ef 100644
--- a/tests/DistanceTest.php
+++ b/tests/DistanceTest.php
@@ -1,132 +1,50 @@
setUnit('mi');
-
- $this->assertEquals('mi', $distance->getUnit());
- }
-
- /**
- * Test the throwing of an exception in case we try to set an invalid unit.
- *
- * @expectedException Exception
- */
- public function testInvalidUnit()
- {
- $distance = new Distance();
-
- $distance->setUnit('mm');
- }
-
- /**
- * Test the setting and getting of the distance formula.
- */
- public function testFormula()
- {
- $distance = new Distance();
- $distance->setFormula('vincenty');
-
- $this->assertEquals('vincenty', $distance->getFormula());
- }
-
- /**
- * Test the throwing of an exception in case we try to set an invalid formula.
- *
- * @expectedException Exception
- */
- public function testInvalidFormula()
- {
- $distance = new Distance();
-
- $distance->setFormula('Leonardo');
- }
-
- /**
- * Test the throwing of an exception in case an invalid parameter is being passed.
- *
- * @expectedException Exception
- */
- public function testInvalidParams()
- {
- $distance = new Distance();
+namespace Tests\ldebrouwer\Distance;
- $distance->between('1', 1, 'not a float', 'invalid');
- }
+use ldebrouwer\Distance\Distance;
+use ldebrouwer\Distance\Formula;
+use ldebrouwer\Distance\Unit;
+use PHPUnit\Framework\Attributes\Test;
+use PHPUnit\Framework\Attributes\TestWith;
+use PHPUnit\Framework\TestCase;
- /**
- * Test the retrieval of the distance between the Apple and Google campuses using the Vincenty formula.
- */
- public function testDistanceBetweenAppleAndGoogleUsingVincenty()
+class DistanceTest extends TestCase
+{
+ private const float LATITUDE_A = 37.331741;
+ private const float LONGITUDE_A = -122.030333;
+ private const float LATITUDE_B = 37.422546;
+ private const float LONGITUDE_B = -122.084250;
+
+ #[Test]
+ #[TestWith([Unit::METRES, 11164.0])]
+ #[TestWith([Unit::KILOMETRES, 11.164])]
+ #[TestWith([Unit::MILES, 6.936987987488])]
+ #[TestWith([Unit::CENTIMETRES, 1116400.0])]
+ #[TestWith([Unit::FEET, 36627.2966436])]
+ #[TestWith([Unit::INCHES, 439527.5586068])]
+ public function canConvertDistanceUsingVincentyFormula(Unit $unit, float $expected): void
{
$distance = new Distance();
- $distance->setUnit('m');
- $distance->setFormula('vincenty');
-
- $this->assertEquals(11164, $distance->between(37.331741, -122.030333, 37.422546, -122.084250));
-
- $distance->setUnit('km');
-
- $this->assertEquals(11.164, $distance->between(37.331741, -122.030333, 37.422546, -122.084250));
-
- $distance->setUnit('mi');
-
- $this->assertEquals(6.936987987488, $distance->between(37.331741, -122.030333, 37.422546, -122.084250));
-
- $distance->setUnit('cm');
-
- $this->assertEquals(1116400, $distance->between(37.331741, -122.030333, 37.422546, -122.084250));
-
- $distance->setUnit('ft');
-
- $this->assertEquals(36627.2966436, $distance->between(37.331741, -122.030333, 37.422546, -122.084250));
+ $distance->setFormula(Formula::VINCENTY);
- $distance->setUnit('in');
-
- $this->assertEquals(439527.5586068, $distance->between(37.331741, -122.030333, 37.422546, -122.084250));
+ self::assertSame($expected, $distance->setUnit($unit)->between(self::LATITUDE_A, self::LONGITUDE_A, self::LATITUDE_B, self::LONGITUDE_B));
}
- /**
- * Test the retrieval of the distance between the Apple and Google campuses using the Haversine formula.
- */
- public function testDistanceBetweenAppleAndGoogleUsingHaversine()
+ #[Test]
+ #[TestWith([Unit::METRES, 11164.0])]
+ #[TestWith([Unit::KILOMETRES, 11.164])]
+ #[TestWith([Unit::MILES, 6.936987987488])]
+ #[TestWith([Unit::CENTIMETRES, 1116400.0])]
+ #[TestWith([Unit::FEET, 36627.2966436])]
+ #[TestWith([Unit::INCHES, 439527.5586068])]
+ public function canConvertDistanceUsingHaversineFormula(Unit $unit, float $expected): void
{
$distance = new Distance();
- $distance->setUnit('m');
- $distance->setFormula('haversine');
-
- $this->assertEquals(11164, $distance->between(37.331741, -122.030333, 37.422546, -122.084250));
-
- $distance->setUnit('km');
-
- $this->assertEquals(11.164, $distance->between(37.331741, -122.030333, 37.422546, -122.084250));
-
- $distance->setUnit('mi');
-
- $this->assertEquals(6.936987987488, $distance->between(37.331741, -122.030333, 37.422546, -122.084250));
-
- $distance->setUnit('cm');
-
- $this->assertEquals(1116400, $distance->between(37.331741, -122.030333, 37.422546, -122.084250));
-
- $distance->setUnit('ft');
-
- $this->assertEquals(36627.2966436, $distance->between(37.331741, -122.030333, 37.422546, -122.084250));
-
- $distance->setUnit('in');
+ $distance->setFormula(Formula::HAVERSINE);
- $this->assertEquals(439527.5586068, $distance->between(37.331741, -122.030333, 37.422546, -122.084250));
+ self::assertSame($expected, $distance->setUnit($unit)->between(self::LATITUDE_A, self::LONGITUDE_A, self::LATITUDE_B, self::LONGITUDE_B));
}
-}
\ No newline at end of file
+}