Skip to content

Commit

Permalink
Add GeographyCast
Browse files Browse the repository at this point in the history
  • Loading branch information
masterix21 committed Dec 2, 2024
1 parent 44df9e8 commit b873124
Show file tree
Hide file tree
Showing 7 changed files with 100 additions and 19 deletions.
2 changes: 1 addition & 1 deletion .phpunit.cache/test-results
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"version":"pest_3.1.0","defects":{"P\\Tests\\Feature\\Models\\AddressTest::__pest_evaluable_it_return_empty_addresses_collection_when_eloquent_has_no_addresses":8,"P\\Tests\\Feature\\Models\\AddressTest::__pest_evaluable_it_fires_billing_address_primary_unmarked_event_on_make_primary":8,"P\\Tests\\Feature\\Models\\AddressTest::__pest_evaluable_it_return_addresses_collection_when_eloquent_has_addresses":8,"P\\Tests\\Feature\\Models\\AddressTest::__pest_evaluable_it_fires_billing_address_primary_marked_event_on_make_primary":8,"P\\Tests\\Feature\\Models\\AddressTest::__pest_evaluable_it_fires_address_primary_unmarked_event_on_make_primary":8,"P\\Tests\\Feature\\Models\\AddressTest::__pest_evaluable_it_fires_shipping_address_primary_unmarked_event_on_make_primary":8,"P\\Tests\\Feature\\Models\\AddressTest::__pest_evaluable_it_fires_shipping_address_primary_marked_event_on_make_primary":8,"P\\Tests\\Feature\\Models\\AddressTest::__pest_evaluable_it_fires_address_primary_marked_event_on_make_primary":8},"times":{"P\\Tests\\Feature\\Models\\AddressTest::__pest_evaluable_it_return_addresses_collection_when_eloquent_has_addresses":0.006,"P\\Tests\\Feature\\Models\\AddressTest::__pest_evaluable_it_fires_address_primary_unmarked_event_on_make_primary":0.004,"P\\Tests\\Feature\\Models\\AddressTest::__pest_evaluable_it_fires_shipping_address_primary_unmarked_event_on_make_primary":0.004,"P\\Tests\\Feature\\Models\\AddressTest::__pest_evaluable_it_fires_address_primary_marked_event_on_make_primary":0.044,"P\\Tests\\Feature\\Models\\AddressTest::__pest_evaluable_it_fires_billing_address_primary_marked_event_on_make_primary":0.007,"P\\Tests\\Feature\\Models\\AddressTest::__pest_evaluable_it_fires_billing_address_primary_unmarked_event_on_make_primary":0.005,"P\\Tests\\Feature\\Models\\AddressTest::__pest_evaluable_it_return_empty_addresses_collection_when_eloquent_has_no_addresses":0.019,"P\\Tests\\Feature\\Models\\AddressTest::__pest_evaluable_it_fires_shipping_address_primary_marked_event_on_make_primary":0.004,"P\\Tests\\ArchTest::__pest_evaluable_it_will_not_use_debugging_functions":0.045}}
{"version":"pest_3.6.0","defects":{"P\\Tests\\Feature\\Models\\AddressTest::__pest_evaluable_it_fires_billing_address_primary_unmarked_event_on_make_primary":8,"P\\Tests\\Feature\\Models\\AddressTest::__pest_evaluable_it_return_addresses_collection_when_eloquent_has_addresses":8,"P\\Tests\\Feature\\Models\\AddressTest::__pest_evaluable_it_fires_shipping_address_primary_unmarked_event_on_make_primary":8,"P\\Tests\\Feature\\Models\\AddressTest::__pest_evaluable_it_fires_billing_address_primary_marked_event_on_make_primary":8,"P\\Tests\\Feature\\Models\\AddressTest::__pest_evaluable_it_fires_address_primary_marked_event_on_make_primary":8,"P\\Tests\\Feature\\Models\\AddressTest::__pest_evaluable_it_fires_address_primary_unmarked_event_on_make_primary":8,"P\\Tests\\Feature\\Models\\AddressTest::__pest_evaluable_it_return_empty_addresses_collection_when_eloquent_has_no_addresses":8,"P\\Tests\\Feature\\Models\\AddressTest::__pest_evaluable_it_fires_shipping_address_primary_marked_event_on_make_primary":8,"P\\Tests\\Feature\\Models\\AddressTest::__pest_evaluable_it_stores_lat_lng":8},"times":{"P\\Tests\\ArchTest::__pest_evaluable_it_will_not_use_debugging_functions":0.055,"P\\Tests\\Feature\\Models\\AddressTest::__pest_evaluable_it_fires_address_primary_unmarked_event_on_make_primary":0.004,"P\\Tests\\Feature\\Models\\AddressTest::__pest_evaluable_it_fires_billing_address_primary_marked_event_on_make_primary":0.004,"P\\Tests\\Feature\\Models\\AddressTest::__pest_evaluable_it_return_addresses_collection_when_eloquent_has_addresses":0.004,"P\\Tests\\Feature\\Models\\AddressTest::__pest_evaluable_it_fires_shipping_address_primary_marked_event_on_make_primary":0.007,"P\\Tests\\Feature\\Models\\AddressTest::__pest_evaluable_it_fires_shipping_address_primary_unmarked_event_on_make_primary":0.005,"P\\Tests\\Feature\\Models\\AddressTest::__pest_evaluable_it_fires_address_primary_marked_event_on_make_primary":0.046,"P\\Tests\\Feature\\Models\\AddressTest::__pest_evaluable_it_return_empty_addresses_collection_when_eloquent_has_no_addresses":0.003,"P\\Tests\\Feature\\Models\\AddressTest::__pest_evaluable_it_fires_billing_address_primary_unmarked_event_on_make_primary":0.004,"P\\Tests\\Feature\\Models\\AddressTest::__pest_evaluable_it_stores_lat_lng":0.004,"P\\Tests\\Feature\\Models\\AddressTest::__pest_evaluable_it_stores_lat_lng_and_retrieve_correctly":0.004,"P\\Tests\\Feature\\Models\\AddressTest::__pest_evaluable_it_stores_and_retrieves_lat_lng_correctly":0.006}}
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
}
],
"require": {
"php": "^8.1|^8.2|^8.3",
"php": "^8.2|^8.3|^8.4",
"illuminate/contracts": "^11.23"
},
"require-dev": {
Expand All @@ -26,6 +26,7 @@
"pestphp/pest": "^3.1",
"pestphp/pest-plugin-arch": "^3.0",
"pestphp/pest-plugin-drift": "3.x-dev",
"pestphp/pest-plugin-faker": "^3.0",
"pestphp/pest-plugin-laravel": "^3.0",
"phpstan/extension-installer": "^1.4",
"phpstan/phpstan-deprecation-rules": "^1.2",
Expand Down
3 changes: 2 additions & 1 deletion database/factories/AddressFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Masterix21\Addressable\Database\Factories;

use Clickbar\Magellan\Data\Geometries\Point;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Database\Eloquent\Model;
use Masterix21\Addressable\Models\Address;
Expand All @@ -23,7 +24,7 @@ public function definition(): array
'city' => $this->faker->city,
'state' => $this->faker->state,
'country' => $this->faker->countryCode,
'coordinates' => [$this->faker->latitude, $this->faker->longitude],
'coordinates' => ['lat' => $this->faker->latitude, 'lng' => $this->faker->longitude],
];
}

Expand Down
52 changes: 36 additions & 16 deletions src/Models/Address.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@

namespace Masterix21\Addressable\Models;

use Illuminate\Database\Eloquent\Casts\AsArrayObject;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Masterix21\Addressable\Models\Casts\GeographyCast;
use Masterix21\Addressable\Models\Concerns\ImplementsMarkPrimary;

class Address extends Model
Expand Down Expand Up @@ -36,23 +37,42 @@ class Address extends Model
'is_primary' => 'bool',
'is_billing' => 'bool',
'is_shipping' => 'bool',
'coordinates' => AsArrayObject::class,
'coordinates' => GeographyCast::class,
];

public function getDisplayAddressAttribute(): string
public function displayAddress(): Attribute
{
$keys = [
'street_address1',
'street_address2',
'zip',
'city',
'state',
'country',
];

return collect($this->getAttributes())
->filter(fn ($item, $key) => in_array($key, $keys) && ! blank($item))
->values()
->join(' - ');
return Attribute::get(function () {
$keys = [
'street_address1',
'street_address2',
'zip',
'city',
'state',
'country',
];

return collect($this->getAttributes())
->filter(fn ($item, $key) => in_array($key, $keys) && ! blank($item))
->values()
->join(' - ');
});
}

public function latitude(): Attribute
{
return Attribute::get(fn () => $this->coordinates['lat'] ?? null);
}

public function longitude(): Attribute
{
return Attribute::get(fn () => $this->coordinates['lng'] ?? null);
}

public function setCoordinates(float $latitude, float $longitude): self
{
$this->coordinates = compact('latitude', 'longitude');

return $this;
}
}
38 changes: 38 additions & 0 deletions src/Models/Casts/GeographyCast.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

namespace Masterix21\Addressable\Models\Casts;

use Illuminate\Contracts\Database\Eloquent\CastsAttributes;

class GeographyCast implements CastsAttributes
{
public function get($model, string $key, $value, array $attributes)
{
if (!$value) {
return null;
}

$coords = sscanf($value, 'POINT(%f %f)');

return [
'lat' => $coords[1],
'lng' => $coords[0],
];
}

public function set($model, string $key, $value, array $attributes)
{
if (! $value) {
return null;
}

$latitude = $value['latitude'] ?? $value['lat'] ?? $value[0] ?? null;
$longitude = $value['longitude'] ?? $value['lng'] ?? $value[1] ?? null;

if ($latitude === null || $longitude === null) {
throw new \InvalidArgumentException('Invalid coordinates format.');
}

return sprintf('POINT(%f %f)', $longitude, $latitude);
}
}
19 changes: 19 additions & 0 deletions tests/Feature/Models/AddressTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,22 @@
Event::assertDispatched(AddressPrimaryUnmarked::class);
Event::assertDispatched(ShippingAddressPrimaryUnmarked::class);
});

it('stores and retrieves lat/lng correctly', function () {
$user = User::factory()->createOne();

$address = Address::factory()->addressable($user)->primary()->shipping()->createOne();

expect($address->latitude)->not->toBeNull()
->and($address->longitude)->not->toBeNull();

$newLat = fake()->latitude();
$newLng = fake()->longitude();

$address
->setCoordinates($newLat, $newLng)
->save();

expect($address->latitude)->toBe($newLat)
->and($address->longitude)->toBe($newLng);
});
2 changes: 2 additions & 0 deletions tests/TestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
namespace Masterix21\Addressable\Tests;

use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Masterix21\Addressable\AddressableServiceProvider;
use Orchestra\Testbench\Concerns\WithLaravelMigrations;
use Orchestra\Testbench\TestCase as Orchestra;

class TestCase extends Orchestra
{
use WithLaravelMigrations;
use RefreshDatabase;

protected function setUp(): void
{
Expand Down

0 comments on commit b873124

Please sign in to comment.