Skip to content

Commit 54a72b9

Browse files
authored
feat: ipquery driver (#72)
* feat: ipquery driver * Fix styling * Trigger Build * update test * update --------- Co-authored-by: pulkitjalan <[email protected]>
1 parent 2c9c922 commit 54a72b9

File tree

5 files changed

+192
-2
lines changed

5 files changed

+192
-2
lines changed

.github/workflows/php-cs-fixer.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
name: pint
22

3-
on: [push]
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
branches:
9+
- main
410

511
jobs:
612
php-cs-fixer:

config/ip-geolocation.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
| IPGeolocation Driver Type
77
|--------------------------------------------------------------------------
88
|
9-
| Supported: "ip-api", "maxmind_database", "maxmind_api", "ipstack"
9+
| Supported: "ip-api", "maxmind_database", "maxmind_api", "ipstack", "ipquery"
1010
|
1111
*/
1212
'driver' => env('IPGEOLOCATION_DRIVER', 'ip-api'),
@@ -85,4 +85,14 @@
8585
// Get your token here: https://ipinfo.io/
8686
'token' => env('IPGEOLOCATION_IPINFO_TOKEN'),
8787
],
88+
89+
/*
90+
|--------------------------------------------------------------------------
91+
| IPQuery Driver
92+
|--------------------------------------------------------------------------
93+
*/
94+
'ipquery' => [
95+
// Get your API key here: https://ipquery.io
96+
'key' => env('IPGEOLOCATION_IPQUERY_KEY'),
97+
],
8898
];

src/Drivers/IPQueryDriver.php

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
<?php
2+
3+
namespace PulkitJalan\IPGeolocation\Drivers;
4+
5+
use Illuminate\Support\Arr;
6+
7+
class IPQueryDriver extends AbstractIPGeolocationDriver implements IPGeolocationInterface
8+
{
9+
/**
10+
* Get array of data using IPQuery.
11+
*
12+
* @param string $ip
13+
* @return array
14+
*/
15+
public function get($ip)
16+
{
17+
$data = $this->getRaw($ip);
18+
19+
if (empty($data) || isset($data['error'])) {
20+
return $this->getDefault();
21+
}
22+
23+
return [
24+
'city' => Arr::get($data, 'location.city'),
25+
'country' => Arr::get($data, 'location.country'),
26+
'countryCode' => Arr::get($data, 'location.country_code'),
27+
'latitude' => (float) number_format(Arr::get($data, 'location.latitude'), 5),
28+
'longitude' => (float) number_format(Arr::get($data, 'location.longitude'), 5),
29+
'region' => Arr::get($data, 'location.state'),
30+
'regionCode' => null, // IPQuery doesn't provide region code
31+
'timezone' => Arr::get($data, 'location.timezone'),
32+
'postalCode' => Arr::get($data, 'location.zipcode'),
33+
];
34+
}
35+
36+
/**
37+
* Get the raw IPGeolocation info using IPQuery.
38+
*
39+
* @param string $ip
40+
* @return array
41+
*/
42+
public function getRaw($ip)
43+
{
44+
return json_decode($this->guzzle->get($this->getUrl($ip))->getBody(), true);
45+
}
46+
47+
/**
48+
* Get the IPQuery API URL with API key.
49+
*
50+
* @param string $ip
51+
* @return string
52+
*/
53+
protected function getUrl($ip)
54+
{
55+
$baseUrl = 'https://api.ipquery.io/';
56+
$key = Arr::get($this->config, 'key');
57+
58+
if (empty($key)) {
59+
throw new \InvalidArgumentException('IPQuery API key is required');
60+
}
61+
62+
return $baseUrl.$ip.'?api_key='.$key;
63+
}
64+
}

src/IPGeolocationManager.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use GuzzleHttp\Client as GuzzleClient;
88
use PulkitJalan\IPGeolocation\Drivers\IPApiDriver;
99
use PulkitJalan\IPGeolocation\Drivers\IPInfoDriver;
10+
use PulkitJalan\IPGeolocation\Drivers\IPQueryDriver;
1011
use PulkitJalan\IPGeolocation\Drivers\IPStackDriver;
1112
use PulkitJalan\IPGeolocation\Drivers\MaxmindApiDriver;
1213
use PulkitJalan\IPGeolocation\Drivers\IP2LocationDriver;
@@ -95,4 +96,12 @@ protected function createIpInfoDriver(array $data): IPInfoDriver
9596
{
9697
return new IPInfoDriver($data, $this->guzzle);
9798
}
99+
100+
/**
101+
* Get the IPQuery driver.
102+
*/
103+
protected function createIpqueryDriver(array $data): IPQueryDriver
104+
{
105+
return new IPQueryDriver($data, $this->guzzle);
106+
}
98107
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
<?php
2+
3+
use GuzzleHttp\Client;
4+
use Mockery\MockInterface;
5+
use GuzzleHttp\Psr7\Response;
6+
use PulkitJalan\IPGeolocation\IPGeolocation;
7+
use PulkitJalan\IPGeolocation\Exceptions\IPGeolocationException;
8+
9+
test('ipquery driver', function () {
10+
$config = [
11+
'driver' => 'ipquery',
12+
'ipquery' => [
13+
'key' => 'test-key',
14+
],
15+
];
16+
17+
/** @var MockInterface|Client $client */
18+
$client = Mockery::mock(Client::class);
19+
20+
$client->shouldReceive('get')
21+
->once()
22+
->andReturn(
23+
new Response(200, [], json_encode([
24+
'location' => [
25+
'city' => 'Los Angeles',
26+
'country' => 'United States',
27+
'country_code' => 'US',
28+
'latitude' => 34.0522,
29+
'longitude' => -118.2437,
30+
'state' => 'California',
31+
'timezone' => 'America/Los_Angeles',
32+
'zipcode' => '90012',
33+
],
34+
]))
35+
);
36+
37+
$ip = new IPGeolocation($config, $client);
38+
$ip = $ip->setIp('8.8.8.8');
39+
40+
expect($ip->get())
41+
->toHaveKey('city', 'Los Angeles')
42+
->toHaveKey('country', 'United States')
43+
->toHaveKey('countryCode', 'US')
44+
->toHaveKey('latitude', 34.05220)
45+
->toHaveKey('longitude', -118.24370)
46+
->toHaveKey('region', 'California')
47+
->toHaveKey('regionCode', null)
48+
->toHaveKey('timezone', 'America/Los_Angeles')
49+
->toHaveKey('postalCode', '90012');
50+
51+
expect('Los Angeles')->toEqual($ip->getCity());
52+
expect('United States')->toEqual($ip->getCountry());
53+
});
54+
55+
test('ipquery driver returns default values when error occurs', function () {
56+
$config = [
57+
'driver' => 'ipquery',
58+
'ipquery' => [
59+
'key' => 'test-key',
60+
],
61+
];
62+
63+
/** @var MockInterface|Client $client */
64+
$client = Mockery::mock(Client::class);
65+
66+
$client->shouldReceive('get')
67+
->once()
68+
->andReturn(
69+
new Response(200, [], json_encode(['error' => 'Invalid IP address']))
70+
);
71+
72+
$ip = new IPGeolocation($config, $client);
73+
$ip = $ip->setIp('invalid-ip');
74+
75+
expect($ip->get())->toEqual([
76+
'city' => null,
77+
'country' => null,
78+
'countryCode' => null,
79+
'latitude' => null,
80+
'longitude' => null,
81+
'region' => null,
82+
'regionCode' => null,
83+
'timezone' => null,
84+
'postalCode' => null,
85+
]);
86+
87+
expect($ip->getCity())->toEqual('');
88+
expect($ip->getCountry())->toEqual('');
89+
});
90+
91+
test('ipquery driver throws exception when api key is missing', function () {
92+
$config = [
93+
'driver' => 'ipquery',
94+
];
95+
96+
$ip = new IPGeolocation($config);
97+
$ip = $ip->setIp('8.8.8.8');
98+
99+
expect(fn () => $ip->get())
100+
->toThrow(IPGeolocationException::class, 'Failed to get ip geolocation data');
101+
});

0 commit comments

Comments
 (0)