Completed
Pull Request — master (#15)
by
unknown
19:42
created

NetAcuity::_parseBody()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 32
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 32
rs 8.8571
c 0
b 0
f 0
cc 1
eloc 27
nc 1
nop 1
1
<?php
2
namespace DominionEnterprises\NetAcuity;
3
4
use DominionEnterprises\Util;
5
use Exception;
6
use GuzzleHttp\Client;
7
use GuzzleHttp\ClientInterface;
8
use GuzzleHttp\Exception\ClientException;
9
use GuzzleHttp\Psr7\Request;
10
11
/**
12
 * A client to access a NetAcuity server for geoip lookup.
13
 */
14
final class NetAcuity
15
{
16
    /**
17
     * @var string Net Acuity's Edge DB Code.
18
     */
19
    const NETACUITY_EDGE_DB_ID = 4;
20
21
    /**
22
     * A Collection of implemented DBs referred to by the NetAcuity DB Id.
23
     */
24
    const IMPLEMENTED_DBS = [
25
        self::NETACUITY_EDGE_DB_ID
26
    ];
27
28
    /**
29
     * @var string The API User token provided by NetAcuity.
30
     */
31
    private $_apiUserToken;
32
33
    /**
34
     * @var Client The Guzzle Client to be used.
35
     */
36
    private $_client;
37
38
    /**
39
     * @var string The NetAcuity database to fetch data from.
40
     */
41
    private $_dbId;
42
43
    /**
44
     * Create the NetAcuity client.
45
     *
46
     * @param ClientInterface $client       The guzzle client to be used. Needs no configuration from the calling application.
47
     * @param string          $apiUserToken The passed in API User Token specific to the calling application or organization.
48
     * @param string          $dbIdentifier The netacuity database identifier, ex: NetAcuity::NETACUITY_EDGE_DB_ID
49
     */
50
    public function __construct(ClientInterface $client, string $apiUserToken, string $dbIdentifier)
51
    {
52
        if (!in_array($dbIdentifier, self::IMPLEMENTED_DBS)) {
53
            throw new Exception("NetAcuity DB Identifier: {$dbIdentifier} not yet supported by this tool.");
54
        }
55
56
        $this->_client = $client;
0 ignored issues
show
Documentation Bug introduced by
$client is of type object<GuzzleHttp\ClientInterface>, but the property $_client was declared to be of type object<GuzzleHttp\Client>. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
57
        $this->_apiUserToken = $apiUserToken;
58
        $this->_dbId = $dbIdentifier;
59
    }
60
61
    /**
62
     * Gets the geo data for the given IP.
63
     *
64
     * Failures will be raised as exceptions.
65
     *
66
     * @param string $ip The ip address to lookup
67
     *
68
     * @return array {
69
     *     @type string $country
70
     *     @type string $region
71
     *     @type string $city
72
     *     @type string $conn-speed
73
     *     @type string $metro-code
74
     *     @type string $latitude
75
     *     @type string $longitude
76
     *     @type string $postal-code
77
     *     @type string $country-code
78
     *     @type string $region-code
79
     *     @type string $city-code
80
     *     @type string $continent-code
81
     *     @type string $two-letter-country
82
     *     @type string $internal-code
83
     *     @type string $area-code
84
     *     @type string $country-conf
85
     *     @type string $region-conf
86
     *     @type string $city-conf
87
     *     @type string $postal-conf
88
     *     @type string $gmt-offset
89
     *     @type string $in-dist
90
     *     @type string $timezone-name
91
     * }
92
     */
93
    public function getGeo(string $ip)
94
    {
95
        Util::throwIfNotType(['string' => $ip], true);
96
97
        $queryString = $this->_buildQuery($this->_apiUserToken, self::NETACUITY_EDGE_DB_ID, $ip);
98
        $request = new Request('GET', $queryString);
99
100
        $body = [];
101
        try {
102
            $response = $this->_client->send($request);
103
            $body = json_decode($response->getBody()->getContents(), true);
104
        } catch (ClientException $e) {
105
            $this->_handleGuzzleException($e);
106
        }
107
108
        return $this->_parseBody($body);
109
    }
110
111
    private function _buildQuery(string $userToken, string $db, string $ip, bool $asJson = true) : string
112
    {
113
        $baseUrl = 'https://usa.cloud.netacuity.com/webservice/query';
114
        $asJsonString = $asJson ? 'true' : 'false';
115
        return "{$baseUrl}?u={$userToken}&dbs={$db}&ip={$ip}&json={$asJsonString}";
116
    }
117
118
    /**
119
     * @param ClientException $e The thrown exception for handling.
120
     *
121
     * @throws Exception A formatted exception masking the API User Token in the event that it becomes invalid.
122
     */
123
    private function _handleGuzzleException(ClientException $e)
124
    {
125
        $response = $e->getResponse();
126
        $code = $response->getStatusCode();
127
128
        if ($code === 403) {
129
            throw new Exception('NetAcuity API rejected the provided api user token.', $code);
130
        }
131
132
        $error = json_decode($response->getBody()->getContents(), true);
133
        $reason = Util\Arrays::getNested($error, 'error.message');
134
135
        throw new Exception("NetAcuity API rejected the request, Reason: {$reason}", $code);
136
    }
137
138
    /**
139
     * Parses the response into an array using the field definition.
140
     *
141
     * @param array $response The response from NetAcuity.
142
     *
143
     * @return array The response where the keys are from $fields and the values are from the $response.
144
     * @throws Exception
145
     */
146
    private function _parseBody(array $response)
147
    {
148
        $responseData = Util\Arrays::get($response, 'response');
149
        $edgeTranslations = [
150
            'area-code' => 'edge-area-codes',
151
            'city' => 'edge-city',
152
            'city-code' => 'edge-city-code',
153
            'city-conf' => 'edge-city-conf',
154
            'conn-speed' => 'edge-conn-speed',
155
            'continent-code' => 'edge-continent-code',
156
            'country' => 'edge-country',
157
            'country-code' => 'edge-country-code',
158
            'country-conf' => 'edge-country-conf',
159
            'gmt-offset' => 'edge-gmt-offset',
160
            'in-dist' => 'edge-in-dst',
161
            'latitude' => 'edge-latitude',
162
            'longitude' => 'edge-longitude',
163
            'metro-code' => 'edge-metro-code',
164
            'postal-conf' => 'edge-postal-conf',
165
            'region' => 'edge-region',
166
            'region-code' => 'edge-region-code',
167
            'region-conf' => 'edge-region-conf',
168
            'timezone-name' => 'edge-timezone-name',
169
            'two-letter-country' => 'edge-two-letter-country',
170
            'zip-code' => 'edge-postal-code',
171
        ];
172
173
        $result = [];
174
        Util\Arrays::copyIfKeysExist($responseData, $result, $edgeTranslations);
175
176
        return $result;
177
    }
178
}
179