Passed
Pull Request — master (#6)
by Teye
13:45
created

DynadotApi   B

Complexity

Total Complexity 46

Size/Duplication

Total Lines 545
Duplicated Lines 0 %

Test Coverage

Coverage 92.98%

Importance

Changes 4
Bugs 0 Features 0
Metric Value
wmc 46
eloc 211
c 4
b 0
f 0
dl 0
loc 545
ccs 212
cts 228
cp 0.9298
rs 8.72

10 Methods

Rating   Name   Duplication   Size   Complexity  
C getDomainList() 0 102 12
B getDomainInfo() 0 96 10
A __construct() 0 51 4
A log() 0 4 2
B setNameserversForDomain() 0 59 7
A getContactInfo() 0 49 5
A performRawApiCall() 0 34 3
A getApiKey() 0 3 1
A setGuzzleOptions() 0 3 1
A setApiKey() 0 3 1

How to fix   Complexity   

Complex Class

Complex classes like DynadotApi often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use DynadotApi, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Level23\Dynadot;
4
5
use Psr\Log\LogLevel;
6
use Sabre\Xml\Reader;
7
use GuzzleHttp\Client;
8
use Sabre\Xml\Service;
9
use Psr\Log\LoggerInterface;
10
use Psr\Http\Message\StreamInterface;
11
use Level23\Dynadot\ResultObjects\SetNsResponse;
12
use Level23\Dynadot\ResultObjects\DomainResponse;
13
use Level23\Dynadot\Exception\DynadotApiException;
14
use Level23\Dynadot\ResultObjects\GeneralResponse;
15
use Level23\Dynadot\ResultObjects\DomainInfoResponse;
16
use Level23\Dynadot\ResultObjects\GetContactResponse;
17
use Level23\Dynadot\Exception\ApiHttpCallFailedException;
18
use Level23\Dynadot\ResultObjects\ListDomainInfoResponse;
19
use Level23\Dynadot\Exception\ApiLimitationExceededException;
20
21
/**
22
 * Class DynadotApi
23
 *
24
 * @package Level23\Dynadot
25
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
26
 */
27
class DynadotApi
28
{
29
    const DYNADOT_API_URL = 'https://api.dynadot.com/api3.xml';
30
31
    /**
32
     * This options array is used by Guzzle.
33
     *
34
     * We currently use it to set the Mock Handler in unit testing.
35
     *
36
     * @var array
37
     */
38
    protected $guzzleOptions = [];
39
40
    /**
41
     * Dynadot's API key we should use for HTTP calls.
42
     *
43
     * @var string
44
     */
45
    protected $apiKey;
46
47
    /**
48
     * Logger for writing debug info
49
     *
50
     * @var LoggerInterface|null
51
     */
52
    protected $logger;
53
54
    /**
55
     * Changes boolean values like "no" and "yes" into false and true.
56
     *
57
     * @return bool
58
     * @throws DynadotApiException
59
     * @var \Closure
60
     */
61
    protected $booleanDeserializer;
62
63
    /**
64
     * Return the contact id
65
     *
66
     * @param Reader $reader
67
     *
68
     * @return int
69
     * @var \Closure
70
     */
71
    protected $contactIdDeserializer;
72
73
    /**
74
     * DynadotApi constructor.
75
     *
76
     * @param string                        $apiKey The API key we should use while communicating with the Dynadot API.
77
     * @param \Psr\Log\LoggerInterface|null $logger
78
     *
79
     * @internal param $Logger
80
     */
81 24
    public function __construct(string $apiKey, LoggerInterface $logger = null)
82
    {
83 24
        $this->setApiKey($apiKey);
84 24
        $this->logger = $logger;
85
86
        /**
87
         * Set the default guzzle options
88
         */
89 24
        $this->setGuzzleOptions([
90 24
            'max'             => 5,
91 24
            'referer'         => false,
92 24
            'protocols'       => ['https'],
93 24
            'connect_timeout' => 30,
94 24
        ]);
95
96
        /**
97
         * Changes boolean values like "no" and "yes" into false and true.
98
         *
99
         * @param \Sabre\Xml\Reader $reader
100
         *
101
         * @return bool
102
         * @throws \Level23\Dynadot\Exception\DynadotApiException
103
         * @throws \Sabre\Xml\LibXMLException
104
         * @throws \Sabre\Xml\ParseException
105
         */
106 24
        $this->booleanDeserializer = function (Reader $reader) {
107 3
            $value = $reader->parseInnerTree();
108 3
            if (is_string($value)) {
109 3
                $value = strtolower($value);
110
            }
111
112 3
            if ($value != 'yes' && $value != 'no') {
113
                throw new DynadotApiException('Error, received incorrect boolean value ' . var_export($value, true));
114
            }
115
116 3
            return ($value !== 'no');
117 24
        };
118
119
        /**
120
         * Return the contact id
121
         *
122
         * @param Reader $reader
123
         *
124
         * @return int
125
         * @throws \Sabre\Xml\LibXMLException
126
         * @throws \Sabre\Xml\ParseException
127
         */
128 24
        $this->contactIdDeserializer = function (Reader $reader) {
129 3
            $children = (array)$reader->parseInnerTree();
130
131 3
            return $children[0]['value'];
132 24
        };
133
    }
134
135
    /**
136
     * @param array $optionsArray
137
     */
138 24
    public function setGuzzleOptions(array $optionsArray): void
139
    {
140 24
        $this->guzzleOptions = $optionsArray;
141
    }
142
143
    /**
144
     * Get info about a domain
145
     *
146
     * @param string $domain
147
     *
148
     * @return DomainResponse\Domain
149
     * @throws \Level23\Dynadot\Exception\ApiHttpCallFailedException
150
     * @throws \Level23\Dynadot\Exception\DynadotApiException
151
     * @throws \Sabre\Xml\ParseException
152
     * @throws \GuzzleHttp\Exception\GuzzleException
153
     */
154 7
    public function getDomainInfo(string $domain): DomainResponse\Domain
155
    {
156 7
        $this->log(LogLevel::INFO, 'Retrieve info for domain: ' . $domain);
157
158 7
        $requestData = [
159 7
            'domain'  => $domain,
160 7
            'command' => 'domain_info',
161 7
        ];
162
163
        // perform the API call
164 7
        $response = $this->performRawApiCall($requestData);
165
166
        // start parsing XML data using Sabre
167 6
        $sabreService = new Service();
168
169
        // set mapping
170 6
        $sabreService->elementMap = [
171 6
            '{}NameServers'          => function (Reader $reader) {
172
173 2
                $nameservers = [];
174 2
                $id          = '';
175
176 2
                $children = (array)$reader->parseInnerTree();
177
178 2
                foreach ($children as $child) {
179 2
                    if ($child['name'] == '{}ServerId') {
180 2
                        $id = $child['value'];
181 2
                    } elseif ($child['name'] == '{}ServerName') {
182 2
                        if (!empty($id) && !empty($child['value'])) {
183 2
                            $nameserver = new DomainResponse\NameServer();
184
185 2
                            $nameserver->ServerId   = $id;
0 ignored issues
show
Documentation Bug introduced by
The property $ServerId was declared of type integer, but $id is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
186 2
                            $nameserver->ServerName = $child['value'];
187
188 2
                            $nameservers[] = $nameserver;
189
                        }
190 2
                        $id = null;
191
                    }
192
                }
193
194 2
                return $nameservers;
195 6
            },
196 6
            '{}Registrant'           => $this->contactIdDeserializer,
197 6
            '{}Admin'                => $this->contactIdDeserializer,
198 6
            '{}Technical'            => $this->contactIdDeserializer,
199 6
            '{}Billing'              => $this->contactIdDeserializer,
200 6
            '{}isForSale'            => $this->booleanDeserializer,
201 6
            '{}Hold'                 => $this->booleanDeserializer,
202 6
            '{}RegistrantUnverified' => $this->booleanDeserializer,
203 6
            '{}UdrpLocked'           => $this->booleanDeserializer,
204 6
            '{}Disabled'             => $this->booleanDeserializer,
205 6
            '{}Locked'               => $this->booleanDeserializer,
206 6
            '{}WithAds'              => $this->booleanDeserializer,
207 6
        ];
208
209
        // map certain values to objects
210 6
        $sabreService->mapValueObject('{}DomainInfoResponse', DomainInfoResponse\DomainInfoResponse::class);
211 6
        $sabreService->mapValueObject('{}DomainInfoHeader', DomainInfoResponse\DomainInfoHeader::class);
212 6
        $sabreService->mapValueObject('{}DomainInfoContent', DomainInfoResponse\DomainInfoContent::class);
213 6
        $sabreService->mapValueObject('{}Domain', DomainResponse\Domain::class);
214 6
        $sabreService->mapValueObject('{}NameServerSettings', DomainResponse\NameServerSettings::class);
215 6
        $sabreService->mapValueObject('{}Whois', DomainResponse\Whois::class);
216 6
        $sabreService->mapValueObject('{}Folder', DomainResponse\Folder::class);
217 6
        $sabreService->mapValueObject('{}Response', GeneralResponse\Response::class);
218 6
        $sabreService->mapValueObject('{}ResponseHeader', GeneralResponse\ResponseHeader::class);
219
220 6
        $this->log(LogLevel::DEBUG, 'Start parsing response XML');
221
222 6
        $contents = $response->getContents();
223
224
        // parse the data
225 6
        $resultData = $sabreService->parse($contents);
226
227 5
        if (!$resultData instanceof DomainInfoResponse\DomainInfoResponse) {
228 2
            throw new DynadotApiException('We failed to parse the response');
229
        }
230
231 3
        $code = $resultData->DomainInfoHeader->ResponseCode ?? $resultData->DomainInfoHeader->SuccessCode;
0 ignored issues
show
Bug introduced by
The property ResponseCode does not seem to exist on Level23\Dynadot\ResultOb...sponse\DomainInfoHeader.
Loading history...
232 3
        if ($code != GeneralResponse\ResponseHeader::RESPONSECODE_OK) {
233 1
            throw new DynadotApiException($resultData->DomainInfoHeader->Error);
234
        }
235
236 2
        if ($resultData->DomainInfoHeader !== null) {
237
            /**
238
             * Check if the API call was successful. If not, return the error
239
             */
240 2
            $code = $resultData->DomainInfoHeader->SuccessCode;
241 2
            if ($code != DomainInfoResponse\DomainInfoHeader::SUCCESSCODE_OK) {
242
                throw new DynadotApiException($resultData->DomainInfoHeader->Error);
243
            }
244
        }
245
246 2
        $this->log(LogLevel::DEBUG, 'Returning domain info');
247
248
        // Here we know our API call was succesful, return the domain info.
249 2
        return $resultData->DomainInfoContent->Domain;
250
    }
251
252
    /**
253
     * Log a message to our logger, if we have any.
254
     *
255
     * @param string $level
256
     * @param string $message
257
     */
258 23
    protected function log(string $level, string $message): void
259
    {
260 23
        if ($this->logger instanceof LoggerInterface) {
261 1
            $this->logger->log($level, $message);
262
        }
263
    }
264
265
    /**
266
     * Performs the actual API call (internal method)
267
     *
268
     * @param array $requestData
269
     *
270
     * @return \Psr\Http\Message\StreamInterface
271
     * @throws \GuzzleHttp\Exception\GuzzleException
272
     * @throws \Level23\Dynadot\Exception\ApiHttpCallFailedException
273
     */
274 22
    protected function performRawApiCall(array $requestData): StreamInterface
275
    {
276 22
        $this->log(LogLevel::DEBUG, 'Perform raw call: ' . var_export($requestData, true));
277
278
        // transform the request data into a valid query string
279 22
        $requestDataHttp = http_build_query($requestData);
280
281
        // spawn Guzzle
282 22
        $client = new Client($this->guzzleOptions);
283
284 22
        $url = self::DYNADOT_API_URL .
285 22
            '?key=' . urlencode($this->getApiKey()) .
286 22
            ($requestDataHttp ? '&' . $requestDataHttp : '');
287
288 22
        $this->log(LogLevel::DEBUG, 'Start new guzzle request with URL: ' . $url);
289
290
        // start a request with out API key and optionally our request data
291 22
        $response = $client->request('GET', $url);
292
293 22
        $this->log(LogLevel::DEBUG, 'Received response with status code ' . $response->getStatusCode());
294
295
        // if we did not get a HTTP 200 response, our HTTP call failed (which is different from a failed API call)
296 22
        if ($response->getStatusCode() != 200) {
297 1
            $this->log(LogLevel::ALERT, 'Received wrong HTTP status code: ' . $response->getStatusCode());
298
            // not ok
299 1
            throw new ApiHttpCallFailedException(
300 1
                'HTTP API call failed, expected 200 status, got ' . $response->getStatusCode()
301 1
            );
302
        }
303
304
        // Return the response body (which is a stream coming from Guzzle).
305
        // Sabre XML semi-handles streams (it will just get the contents of the stream using stream_get_contents) so
306
        // this should work! ;)
307 21
        return $response->getBody();
308
    }
309
310
    /**
311
     * @return string
312
     */
313 23
    public function getApiKey(): string
314
    {
315 23
        return $this->apiKey;
316
    }
317
318
    /**
319
     * @param string $apiKey
320
     */
321 24
    public function setApiKey(string $apiKey): void
322
    {
323 24
        $this->apiKey = $apiKey;
324
    }
325
326
    /**
327
     * Set nameservers for a domain (max 13). An exception will be thrown in case of an error.
328
     *
329
     * @param string $domain The domain where to set the nameservers for.
330
     * @param array  $nameservers
331
     *
332
     * @throws \GuzzleHttp\Exception\GuzzleException
333
     * @throws \Level23\Dynadot\Exception\ApiHttpCallFailedException
334
     * @throws \Level23\Dynadot\Exception\ApiLimitationExceededException
335
     * @throws \Level23\Dynadot\Exception\DynadotApiException
336
     * @throws \Sabre\Xml\ParseException
337
     */
338 6
    public function setNameserversForDomain(string $domain, array $nameservers): void
339
    {
340 6
        $this->log(LogLevel::DEBUG, 'Set ' . sizeof($nameservers) . ' nameservers for domain ' . $domain);
341 6
        $requestData = [
342 6
            'command' => 'set_ns',
343 6
            'domain'  => $domain,
344 6
        ];
345
346 6
        if (sizeof($nameservers) > 13) {
347
            // index starts at 0, so we should check if the index is greater than 12 (which is 13 nameservers)
348 1
            throw new ApiLimitationExceededException(
349 1
                'Can not define more than 13 nameservers through the API'
350 1
            );
351
        }
352
353 5
        $idx = 0;
354
        // check if there are more than 13 nameservers defined
355 5
        foreach ($nameservers as $nameserver) {
356 5
            $requestData['ns' . $idx++] = $nameserver;
357
        }
358
359
        // perform the API call
360 5
        $response = $this->performRawApiCall($requestData);
361
362 5
        $this->log(LogLevel::DEBUG, 'API call executed, parsing response...');
363
364
        // start parsing XML data using Sabre
365 5
        $sabreService = new Service();
366
367
        // map certain values to objects
368 5
        $sabreService->mapValueObject('{}SetNsResponse', SetNsResponse\SetNsResponse::class);
369 5
        $sabreService->mapValueObject('{}SetNsHeader', SetNsResponse\SetNsHeader::class);
370 5
        $sabreService->mapValueObject('{}Response', GeneralResponse\Response::class);
371 5
        $sabreService->mapValueObject('{}ResponseHeader', GeneralResponse\ResponseHeader::class);
372
373
        // parse the data
374 5
        $resultData = $sabreService->parse($response->getContents());
375
376
        // General error, like incorrect api key
377 4
        if ($resultData instanceof GeneralResponse\Response) {
378 1
            $code = $resultData->ResponseHeader->ResponseCode;
379 1
            if ($code != GeneralResponse\ResponseHeader::RESPONSECODE_OK) {
380 1
                throw new DynadotApiException($resultData->ResponseHeader->Error);
381
            }
382
        }
383
384 3
        if (!$resultData instanceof SetNsResponse\SetNsResponse) {
385 1
            throw new DynadotApiException('We failed to parse the response');
386
        }
387
388
        /**
389
         * Check if the API call was successful. If not, return the error
390
         */
391 2
        $code = $resultData->SetNsHeader->SuccessCode;
392 2
        if ($code != SetNsResponse\SetNsHeader::SUCCESSCODE_OK) {
393 1
            throw new DynadotApiException($resultData->SetNsHeader->Error);
394
        }
395
396 1
        $this->log(LogLevel::DEBUG, 'Received correct response. Everything is ok!');
397
    }
398
399
    /**
400
     * List all domains in the account. We will return an array with Domain objects
401
     *
402
     * @return DomainResponse\Domain[]
403
     * @throws \GuzzleHttp\Exception\GuzzleException
404
     * @throws \Level23\Dynadot\Exception\ApiHttpCallFailedException
405
     * @throws \Level23\Dynadot\Exception\DynadotApiException
406
     * @throws \Sabre\Xml\ParseException
407
     */
408 5
    public function getDomainList(): array
409
    {
410 5
        $this->log(LogLevel::DEBUG, 'Start retrieving all domains');
411 5
        $requestData = [
412 5
            'command' => 'list_domain',
413 5
        ];
414
415
        // perform the API call
416 5
        $response = $this->performRawApiCall($requestData);
417
418 5
        $this->log(LogLevel::DEBUG, 'Start parsing response XML');
419
420
        // start parsing XML data using Sabre
421 5
        $sabreService = new Service();
422
423
        // set mapping
424 5
        $sabreService->elementMap = [
425 5
            '{}NameServers'          => function (Reader $reader) {
426
427
                $nameservers = [];
428
                $id          = '';
429
430
                $children = (array)$reader->parseInnerTree();
431
432
                foreach ($children as $child) {
433
                    if ($child['name'] == '{}ServerId') {
434
                        $id = $child['value'];
435
                    } elseif ($child['name'] == '{}ServerName') {
436
                        if (!empty($id) && !empty($child['value'])) {
437
                            $nameserver             = new DomainResponse\NameServer();
438
                            $nameserver->ServerId   = $id;
0 ignored issues
show
Documentation Bug introduced by
The property $ServerId was declared of type integer, but $id is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
439
                            $nameserver->ServerName = $child['value'];
440
441
                            $nameservers[] = $nameserver;
442
                        }
443
                        $id = null;
444
                    }
445
                }
446
447
                return $nameservers;
448 5
            },
449 5
            '{}DomainInfoList'       => function (Reader $reader) {
450 1
                $domains = [];
451
452 1
                $tree = (array)$reader->parseInnerTree();
453
454 1
                foreach ($tree as $item) {
455 1
                    foreach ($item['value'] as $domain) {
456 1
                        $domains[] = $domain['value'];
457
                    }
458
                }
459
460 1
                return $domains;
461 5
            },
462 5
            '{}Registrant'           => $this->contactIdDeserializer,
463 5
            '{}Admin'                => $this->contactIdDeserializer,
464 5
            '{}Technical'            => $this->contactIdDeserializer,
465 5
            '{}Billing'              => $this->contactIdDeserializer,
466 5
            '{}isForSale'            => $this->booleanDeserializer,
467 5
            '{}Hold'                 => $this->booleanDeserializer,
468 5
            '{}RegistrantUnverified' => $this->booleanDeserializer,
469 5
            '{}UdrpLocked'           => $this->booleanDeserializer,
470 5
            '{}Disabled'             => $this->booleanDeserializer,
471 5
            '{}Locked'               => $this->booleanDeserializer,
472 5
            '{}WithAds'              => $this->booleanDeserializer,
473 5
        ];
474
475
        // map certain values to objects
476 5
        $sabreService->mapValueObject('{}ListDomainInfoResponse', ListDomainInfoResponse\ListDomainInfoResponse::class);
477 5
        $sabreService->mapValueObject('{}ListDomainInfoHeader', ListDomainInfoResponse\ListDomainInfoHeader::class);
478 5
        $sabreService->mapValueObject('{}ListDomainInfoContent', ListDomainInfoResponse\ListDomainInfoContent::class);
479 5
        $sabreService->mapValueObject('{}Domain', DomainResponse\Domain::class);
480 5
        $sabreService->mapValueObject('{}NameServerSettings', DomainResponse\NameServerSettings::class);
481 5
        $sabreService->mapValueObject('{}Whois', DomainResponse\Whois::class);
482 5
        $sabreService->mapValueObject('{}Folder', DomainResponse\Folder::class);
483 5
        $sabreService->mapValueObject('{}Response', GeneralResponse\Response::class);
484 5
        $sabreService->mapValueObject('{}ResponseHeader', GeneralResponse\ResponseHeader::class);
485
486
        // parse the data
487 5
        $resultData = $sabreService->parse($response->getContents());
488
489
        // General error, like incorrect api key
490 4
        if ($resultData instanceof GeneralResponse\Response) {
491 1
            $code = $resultData->ResponseHeader->ResponseCode;
492 1
            if ($code != GeneralResponse\ResponseHeader::RESPONSECODE_OK) {
493 1
                throw new DynadotApiException($resultData->ResponseHeader->Error);
494
            }
495
        }
496
497 3
        if (!$resultData instanceof ListDomainInfoResponse\ListDomainInfoResponse) {
498 1
            throw new DynadotApiException('We failed to parse the response');
499
        }
500
501
        /**
502
         * Check if the API call was successful. If not, return the error
503
         */
504 2
        $code = $resultData->ListDomainInfoHeader->ResponseCode;
505 2
        if ($code != ListDomainInfoResponse\ListDomainInfoHeader::RESPONSECODE_OK) {
506 1
            throw new DynadotApiException($resultData->ListDomainInfoHeader->Error);
507
        }
508
509 1
        return $resultData->ListDomainInfoContent->DomainInfoList;
510
    }
511
512
    /**
513
     * Get contact information for a specific contact ID
514
     *
515
     * @param int $contactId The contact ID we should request
516
     *
517
     * @return GetContactResponse\Contact
518
     * @throws \GuzzleHttp\Exception\GuzzleException
519
     * @throws \Level23\Dynadot\Exception\ApiHttpCallFailedException
520
     * @throws \Level23\Dynadot\Exception\DynadotApiException
521
     * @throws \Sabre\Xml\ParseException
522
     */
523 5
    public function getContactInfo(int $contactId): GetContactResponse\Contact
524
    {
525 5
        $this->log(LogLevel::DEBUG, 'Fetch contact details for id ' . $contactId);
526
527 5
        $requestData = [
528 5
            'command'    => 'get_contact',
529 5
            'contact_id' => $contactId,
530 5
        ];
531
532
        // perform the API call
533 5
        $response = $this->performRawApiCall($requestData);
534
535 5
        $this->log(LogLevel::DEBUG, 'Start parsing result');
536
537
        // start parsing XML data using Sabre
538 5
        $sabreService = new Service();
539
540
        // map certain values to objects
541 5
        $sabreService->mapValueObject('{}GetContactResponse', GetContactResponse\GetContactResponse::class);
542 5
        $sabreService->mapValueObject('{}GetContactHeader', GetContactResponse\GetContactHeader::class);
543 5
        $sabreService->mapValueObject('{}GetContactContent', GetContactResponse\GetContactContent::class);
544 5
        $sabreService->mapValueObject('{}Contact', GetContactResponse\Contact::class);
545 5
        $sabreService->mapValueObject('{}Response', GeneralResponse\Response::class);
546 5
        $sabreService->mapValueObject('{}ResponseHeader', GeneralResponse\ResponseHeader::class);
547
548
        // parse the data
549 5
        $resultData = $sabreService->parse($response->getContents());
550
551
        // General error, like incorrect api key
552 4
        if ($resultData instanceof GeneralResponse\Response) {
553 1
            $code = $resultData->ResponseHeader->ResponseCode;
554 1
            if ($code != GeneralResponse\ResponseHeader::RESPONSECODE_OK) {
555 1
                throw new DynadotApiException($resultData->ResponseHeader->Error);
556
            }
557
        }
558
559 3
        if (!$resultData instanceof GetContactResponse\GetContactResponse) {
560 1
            throw new DynadotApiException('We failed to parse the response');
561
        }
562
563
        /**
564
         * Check if the API call was successful. If not, return the error
565
         */
566 2
        $code = $resultData->GetContactHeader->ResponseCode;
567 2
        if ($code != GetContactResponse\GetContactHeader::RESPONSECODE_OK) {
568 1
            throw new DynadotApiException($resultData->GetContactHeader->Error);
569
        }
570
571 1
        return $resultData->GetContactContent->Contact;
572
    }
573
}
574