Skip to content

Commit 8d7a5eb

Browse files
committed
Integrate matanyadaev/laravel-eloquent-spatial
1 parent b873124 commit 8d7a5eb

File tree

9 files changed

+99
-79
lines changed

9 files changed

+99
-79
lines changed

.phpunit.cache/test-results

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"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}}
1+
{"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,"P\\Tests\\Feature\\Models\\AddressTest::__pest_evaluable_it_retrieves_all_address_within_10_km":8,"P\\Tests\\Feature\\Models\\AddressTest::__pest_evaluable_it_stores_and_retrieves_lat_lng_correctly":8,"P\\Tests\\ArchTest::__pest_evaluable_it_will_not_use_debugging_functions":7},"times":{"P\\Tests\\ArchTest::__pest_evaluable_it_will_not_use_debugging_functions":0.064,"P\\Tests\\Feature\\Models\\AddressTest::__pest_evaluable_it_fires_address_primary_unmarked_event_on_make_primary":0.021,"P\\Tests\\Feature\\Models\\AddressTest::__pest_evaluable_it_fires_billing_address_primary_marked_event_on_make_primary":0.018,"P\\Tests\\Feature\\Models\\AddressTest::__pest_evaluable_it_return_addresses_collection_when_eloquent_has_addresses":0.026,"P\\Tests\\Feature\\Models\\AddressTest::__pest_evaluable_it_fires_shipping_address_primary_marked_event_on_make_primary":0.024,"P\\Tests\\Feature\\Models\\AddressTest::__pest_evaluable_it_fires_shipping_address_primary_unmarked_event_on_make_primary":0.025,"P\\Tests\\Feature\\Models\\AddressTest::__pest_evaluable_it_fires_address_primary_marked_event_on_make_primary":0.089,"P\\Tests\\Feature\\Models\\AddressTest::__pest_evaluable_it_return_empty_addresses_collection_when_eloquent_has_no_addresses":0.026,"P\\Tests\\Feature\\Models\\AddressTest::__pest_evaluable_it_fires_billing_address_primary_unmarked_event_on_make_primary":0.029,"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.029,"P\\Tests\\Feature\\Models\\AddressTest::__pest_evaluable_it_retrieves_all_address_within_10_km":0.089}}

README.md

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
This package adds to any Eloquent model the addresses: in this way will be easier to support a billing address, the shipment addresses or others.
99

10+
It uses the great package `matanyadaev/laravel-eloquent-spatial` by Matan Yadaev.
11+
1012
## Support us
1113

1214
If you like my work, you can [sponsoring me](https://github.com/masterix21).
@@ -98,13 +100,23 @@ $billingAddress->save();
98100
```php
99101
// Take all addresses within 10 km
100102
$addresses = Address::query()
101-
->withPositionDistance(new Point(38.90852, 16.5894), 10000)
102-
->get();
103+
->whereDistanceSphere(
104+
column: 'coordinates',
105+
geometryOrColumn: new Point(45.4391, 9.1906, config('addressable.srid')),
106+
operator: '<=',
107+
value: 10_000
108+
)
109+
->get();
103110

104111
// Take all addresses over 10 km
105112
$addresses = Address::query()
106-
->withPositionDistance(new Point(38.90852, 16.5894), 10000, '>=')
107-
->get();
113+
->whereDistanceSphere(
114+
column: 'coordinates',
115+
geometryOrColumn: new Point(45.4391, 9.1906, config('addressable.srid')),
116+
operator: '>=',
117+
value: 10_000
118+
)
119+
->get();
108120
```
109121

110122
## Testing
@@ -131,6 +143,7 @@ If you discover any security related issues, please email [email protected] inst
131143
## Credits
132144

133145
- [Luca Longo](https://github.com/masterix21)
146+
- [Matan Yadaev](https://github.com/MatanYadaev/laravel-eloquent-spatial)
134147
- [All Contributors](../../contributors)
135148

136149
## License

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
],
1818
"require": {
1919
"php": "^8.2|^8.3|^8.4",
20-
"illuminate/contracts": "^11.23"
20+
"illuminate/contracts": "^11.23",
21+
"matanyadaev/laravel-eloquent-spatial": "^4.4"
2122
},
2223
"require-dev": {
2324
"larastan/larastan": "^2.9",

database/factories/AddressFactory.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22

33
namespace Masterix21\Addressable\Database\Factories;
44

5-
use Clickbar\Magellan\Data\Geometries\Point;
65
use Illuminate\Database\Eloquent\Factories\Factory;
76
use Illuminate\Database\Eloquent\Model;
87
use Masterix21\Addressable\Models\Address;
8+
use MatanYadaev\EloquentSpatial\Objects\Point;
99

1010
class AddressFactory extends Factory
1111
{
@@ -24,7 +24,11 @@ public function definition(): array
2424
'city' => $this->faker->city,
2525
'state' => $this->faker->state,
2626
'country' => $this->faker->countryCode,
27-
'coordinates' => ['lat' => $this->faker->latitude, 'lng' => $this->faker->longitude],
27+
'coordinates' => new Point(
28+
latitude: $this->faker->latitude,
29+
longitude: $this->faker->longitude,
30+
srid: config('addressable.srid')
31+
),
2832
];
2933
}
3034

phpunit.xml.dist

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,12 @@
2828
<directory suffix=".php">./src</directory>
2929
</include>
3030
</source>
31+
<php>
32+
<env name="DB_CONNECTION" value="mysql"/>
33+
<env name="DB_HOST" value="127.0.0.1"/>
34+
<env name="DB_PORT" value="3306"/>
35+
<env name="DB_DATABASE" value="test"/>
36+
<env name="DB_USERNAME" value="root"/>
37+
<env name="DB_PASSWORD" value=""/>
38+
</php>
3139
</phpunit>

src/Models/Address.php

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,18 @@
22

33
namespace Masterix21\Addressable\Models;
44

5+
use Illuminate\Database\Eloquent\Builder;
56
use Illuminate\Database\Eloquent\Casts\Attribute;
67
use Illuminate\Database\Eloquent\Factories\HasFactory;
78
use Illuminate\Database\Eloquent\Model;
8-
use Masterix21\Addressable\Models\Casts\GeographyCast;
99
use Masterix21\Addressable\Models\Concerns\ImplementsMarkPrimary;
10+
use MatanYadaev\EloquentSpatial\Objects\Point;
11+
use MatanYadaev\EloquentSpatial\Traits\HasSpatial;
1012

1113
class Address extends Model
1214
{
1315
use HasFactory;
16+
use HasSpatial;
1417
use ImplementsMarkPrimary;
1518

1619
protected $fillable = [
@@ -37,9 +40,11 @@ class Address extends Model
3740
'is_primary' => 'bool',
3841
'is_billing' => 'bool',
3942
'is_shipping' => 'bool',
40-
'coordinates' => GeographyCast::class,
43+
'coordinates' => Point::class,
4144
];
4245

46+
47+
4348
public function displayAddress(): Attribute
4449
{
4550
return Attribute::get(function () {
@@ -58,21 +63,4 @@ public function displayAddress(): Attribute
5863
->join(' - ');
5964
});
6065
}
61-
62-
public function latitude(): Attribute
63-
{
64-
return Attribute::get(fn () => $this->coordinates['lat'] ?? null);
65-
}
66-
67-
public function longitude(): Attribute
68-
{
69-
return Attribute::get(fn () => $this->coordinates['lng'] ?? null);
70-
}
71-
72-
public function setCoordinates(float $latitude, float $longitude): self
73-
{
74-
$this->coordinates = compact('latitude', 'longitude');
75-
76-
return $this;
77-
}
7866
}

src/Models/Casts/GeographyCast.php

Lines changed: 0 additions & 38 deletions
This file was deleted.

tests/Feature/Models/AddressTest.php

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use Masterix21\Addressable\Models\Address;
1111
use Masterix21\Addressable\Tests\TestCase;
1212
use Masterix21\Addressable\Tests\TestClasses\User;
13+
use MatanYadaev\EloquentSpatial\Objects\Point;
1314

1415
uses(TestCase::class);
1516

@@ -107,16 +108,56 @@
107108

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

110-
expect($address->latitude)->not->toBeNull()
111-
->and($address->longitude)->not->toBeNull();
111+
expect($address->coordinates->latitude)->not->toBeNull()
112+
->and($address->coordinates->longitude)->not->toBeNull();
112113

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

116-
$address
117-
->setCoordinates($newLat, $newLng)
118-
->save();
117+
$address->coordinates = new Point($newLat, $newLng, config('addressable.srid'));
118+
$address->save();
119119

120-
expect($address->latitude)->toBe($newLat)
121-
->and($address->longitude)->toBe($newLng);
120+
expect($address->coordinates->latitude)->toBe($newLat)
121+
->and($address->coordinates->longitude)->toBe($newLng);
122+
});
123+
124+
it('retrieves all address within 10 km', function () {
125+
$user = User::factory()->createOne();
126+
127+
$homeAddress = Address::factory()->addressable($user)
128+
->state(['coordinates' => new Point(45.4642, 9.19, config('addressable.srid'))])
129+
->createOne();
130+
131+
// Within 10km
132+
Address::factory()->addressable($user)->state(['coordinates' => new Point(45.4391, 9.1906, config('addressable.srid'))])->createOne();
133+
Address::factory()->addressable($user)->state(['coordinates' => new Point(45.4535, 9.1898, config('addressable.srid'))])->createOne();
134+
Address::factory()->addressable($user)->state(['coordinates' => new Point(45.4940, 9.1893, config('addressable.srid'))])->createOne();
135+
136+
// Within 20km
137+
Address::factory()->addressable($user)->state(['coordinates' => new Point(45.5436, 9.4197, config('addressable.srid'))])->createOne();
138+
Address::factory()->addressable($user)->state(['coordinates' => new Point(45.6374, 9.2595, config('addressable.srid'))])->createOne();
139+
140+
$result = Address::query()
141+
->where('id', '!=', $homeAddress->id)
142+
->whereDistanceSphere(
143+
column: 'coordinates',
144+
geometryOrColumn: new Point(45.4391, 9.1906, config('addressable.srid')),
145+
operator: '<=',
146+
value: 10_000
147+
)
148+
->count();
149+
150+
expect($result)->toBe(3);
151+
152+
$result = Address::query()
153+
->where('id', '!=', $homeAddress->id)
154+
->whereDistanceSphere(
155+
column: 'coordinates',
156+
geometryOrColumn: new Point(45.4391, 9.1906, config('addressable.srid')),
157+
operator: '>=',
158+
value: 10_000
159+
)
160+
->count();
161+
162+
expect($result)->toBe(2);
122163
});

tests/TestCase.php

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ function (string $modelName) {
2222
return 'Masterix21\\Addressable\\Database\\Factories\\'.class_basename($modelName).'Factory';
2323
}
2424
);
25+
26+
$this->migrateDb();
2527
}
2628

2729
protected function getPackageProviders($app): array
@@ -33,14 +35,15 @@ protected function getPackageProviders($app): array
3335

3436
public function getEnvironmentSetUp($app): void
3537
{
36-
$app['config']->set('database.default', 'sqlite');
37-
$app['config']->set('database.connections.sqlite', [
38-
'driver' => 'sqlite',
39-
'database' => ':memory:',
40-
'prefix' => '',
38+
$app['config']->set('database.default', 'mysql');
39+
$app['config']->set('database.connections.mysql', [
40+
'driver' => 'mysql',
41+
'username' => env('DB_USERNAME', 'root'),
42+
'host' => env('DB_HOST', '127.0.0.1'),
43+
'port' => env('DB_PORT', '3306'),
44+
'password' => env('DB_PASSWORD'),
45+
'database' => env('DB_NAME', 'test'),
4146
]);
42-
43-
$this->migrateDb();
4447
}
4548

4649
public function migrateDb(): void

0 commit comments

Comments
 (0)