DynadotApi::setNameserversForDomain()   B
last analyzed

Complexity

Conditions 7
Paths 15

Size

Total Lines 65
Code Lines 31

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 35
CRAP Score 7

Importance

Changes 0
Metric Value
eloc 31
c 0
b 0
f 0
dl 0
loc 65
ccs 35
cts 35
cp 1
rs 8.4906
cc 7
nc 15
nop 2
crap 7

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Level23\Dynadot;
4
5
use Closure;
6
use Psr\Log\LogLevel;
7
use Sabre\Xml\Reader;
8
use GuzzleHttp\Client;
9
use Sabre\Xml\Service;
10
use Psr\Log\LoggerInterface;
11
use Psr\Http\Message\StreamInterface;
12
use Level23\Dynadot\ResultObjects\SetNsResponse;
13
use Level23\Dynadot\ResultObjects\DomainResponse;
14
use Level23\Dynadot\Exception\DynadotApiException;
15
use Level23\Dynadot\ResultObjects\GeneralResponse;
16
use Level23\Dynadot\ResultObjects\DomainInfoResponse;
17
use Level23\Dynadot\ResultObjects\GetContactResponse;
18
use Level23\Dynadot\Exception\ApiHttpCallFailedException;
19
use Level23\Dynadot\ResultObjects\ListDomainInfoResponse;
20
use Level23\Dynadot\Exception\ApiLimitationExceededException;
21
use Level23\Dynadot\ResultObjects\RenewOptionResponse\SetRenewOptionHeader;
22
use Level23\Dynadot\ResultObjects\RenewOptionResponse\SetRenewOptionResponse;
23
24
/**
25
 * Class DynadotApi
26
 *
27
 * @package Level23\Dynadot
28
 */
29
class DynadotApi
30
{
31
    const DYNADOT_API_URL = 'https://api.dynadot.com/api3.xml';
32
33
    /**
34
     * This option array is used by Guzzle.
35
     *
36
     * We currently use it to set the Mock Handler in unit testing.
37
     *
38
     * @var array<int|string,mixed>
39
     */
40
    protected array $guzzleOptions = [];
41
42
    /**
43
     * Dynadot's API key we should use for HTTP calls.
44
     *
45
     * @var string
46
     */
47
    protected string $apiKey;
48
49
    /**
50
     * Logger for writing debug info
51
     *
52
     * @var LoggerInterface|null
53
     */
54
    protected ?LoggerInterface $logger;
55
56
    /**
57
     * Changes boolean values like "no" and "yes" into false and true.
58
     */
59
    protected Closure $booleanDeserializer;
60
61
    /**
62
     * Change a value to an integer.
63
     */
64
    protected Closure $intDeserializer;
65
66
    /**
67
     * Return the contact id
68
     */
69
    protected Closure $contactIdDeserializer;
70
71
    /**
72
     * DynadotApi constructor.
73
     *
74
     * @param string                        $apiKey The API key we should use while communicating with the Dynadot API.
75
     * @param \Psr\Log\LoggerInterface|null $logger
76
     *
77
     * @internal param $Logger
78
     */
79 28
    public function __construct(string $apiKey, ?LoggerInterface $logger = null)
80
    {
81 28
        $this->setApiKey($apiKey);
82 28
        $this->logger = $logger;
83
84
        /**
85
         * Set the default guzzle options
86
         */
87 28
        $this->setGuzzleOptions([
88 28
            'max'             => 5,
89 28
            'referer'         => false,
90 28
            'protocols'       => ['https'],
91 28
            'connect_timeout' => 30,
92 28
        ]);
93
94
        /**
95
         * Changes boolean values like "no" and "yes" into false and true.
96
         *
97
         * @param \Sabre\Xml\Reader $reader
98
         *
99
         * @return bool
100
         * @throws \Level23\Dynadot\Exception\DynadotApiException
101
         * @throws \Sabre\Xml\LibXMLException
102
         * @throws \Sabre\Xml\ParseException
103
         */
104 28
        $this->booleanDeserializer = function (Reader $reader): bool {
105 3
            $value = $reader->parseInnerTree();
106 3
            if (is_string($value)) {
107 3
                $value = strtolower($value);
108
            }
109
110 3
            if ($value != 'yes' && $value != 'no') {
111
                throw new DynadotApiException('Error, received incorrect boolean value ' . var_export($value, true));
112
            }
113
114 3
            return ($value !== 'no');
115 28
        };
116
117
        /**
118
         * Changes values to an integer.
119
         *
120
         * @param \Sabre\Xml\Reader $reader
121
         *
122
         * @return int
123
         * @throws \Level23\Dynadot\Exception\DynadotApiException
124
         * @throws \Sabre\Xml\LibXMLException
125
         * @throws \Sabre\Xml\ParseException
126
         */
127 28
        $this->intDeserializer = function (Reader $reader): int {
128 15
            $value = $reader->parseInnerTree();
129 15
            if (is_numeric($value)) {
130 15
                return (int)$value;
131
            }
132
133
            throw new DynadotApiException('Error, received incorrect integer value ' . var_export($value, true));
134 28
        };
135
136
        /**
137
         * Return the contact id
138
         *
139
         * @param Reader $reader
140
         *
141
         * @return int
142
         * @throws \Sabre\Xml\LibXMLException
143
         * @throws \Sabre\Xml\ParseException
144
         */
145 28
        $this->contactIdDeserializer = function (Reader $reader): int {
146 3
            $children = (array)$reader->parseInnerTree();
147
148 3
            return (int)$children[0]['value'];
149 28
        };
150
    }
151
152
    /**
153
     * @param array<int|string,mixed> $optionsArray
154
     */
155 28
    public function setGuzzleOptions(array $optionsArray): void
156
    {
157 28
        $this->guzzleOptions = $optionsArray;
158
    }
159
160
    /**
161
     * Get info about a domain
162
     *
163
     * @param string $domain
164
     *
165
     * @return DomainResponse\Domain
166
     * @throws \Level23\Dynadot\Exception\ApiHttpCallFailedException
167
     * @throws \Level23\Dynadot\Exception\DynadotApiException
168
     * @throws \Sabre\Xml\ParseException
169
     * @throws \GuzzleHttp\Exception\GuzzleException
170
     */
171 7
    public function getDomainInfo(string $domain): DomainResponse\Domain
172
    {
173 7
        $this->log(LogLevel::INFO, 'Retrieve info for domain: ' . $domain);
174
175 7
        $requestData = [
176 7
            'domain'  => $domain,
177 7
            'command' => 'domain_info',
178 7
        ];
179
180
        // perform the API call
181 7
        $response = $this->performRawApiCall($requestData);
182
183
        // start parsing XML data using Sabre
184 6
        $sabreService = new Service();
185
186
        // set mapping
187 6
        $sabreService->elementMap = [
188 6
            '{}Registrant'           => $this->contactIdDeserializer,
189 6
            '{}Admin'                => $this->contactIdDeserializer,
190 6
            '{}Technical'            => $this->contactIdDeserializer,
191 6
            '{}Billing'              => $this->contactIdDeserializer,
192 6
            '{}isForSale'            => $this->booleanDeserializer,
193 6
            '{}Hold'                 => $this->booleanDeserializer,
194 6
            '{}RegistrantUnverified' => $this->booleanDeserializer,
195 6
            '{}UdrpLocked'           => $this->booleanDeserializer,
196 6
            '{}Disabled'             => $this->booleanDeserializer,
197 6
            '{}Locked'               => $this->booleanDeserializer,
198 6
            '{}WithAds'              => $this->booleanDeserializer,
199 6
            '{}ResponseCode'         => $this->intDeserializer,
200 6
        ];
201
202
        // map certain values to objects
203 6
        $sabreService->mapValueObject('{}DomainInfoResponse', DomainInfoResponse\DomainInfoResponse::class);
204 6
        $sabreService->mapValueObject('{}DomainInfoHeader', DomainInfoResponse\DomainInfoHeader::class);
205 6
        $sabreService->mapValueObject('{}DomainInfoContent', DomainInfoResponse\DomainInfoContent::class);
206 6
        $sabreService->mapValueObject('{}Domain', DomainResponse\Domain::class);
207 6
        $sabreService->mapValueObject('{}NameServerSettings', DomainResponse\NameServerSettings::class);
208 6
        $sabreService->mapValueObject('{}NameServer', DomainResponse\NameServer::class);
209 6
        $sabreService->mapValueObject('{}Whois', DomainResponse\Whois::class);
210 6
        $sabreService->mapValueObject('{}Folder', DomainResponse\Folder::class);
211 6
        $sabreService->mapValueObject('{}Response', GeneralResponse\Response::class);
212 6
        $sabreService->mapValueObject('{}ResponseHeader', GeneralResponse\ResponseHeader::class);
213
214 6
        $this->log(LogLevel::DEBUG, 'Start parsing response XML');
215
216 6
        $contents = $response->getContents();
217
218
        // parse the data
219 6
        $resultData = $sabreService->parse($contents);
220
221 5
        if (!$resultData instanceof DomainInfoResponse\DomainInfoResponse) {
222 2
            throw new DynadotApiException('We failed to parse the response');
223
        }
224
225 3
        $code = $resultData->DomainInfoHeader->ResponseCode ?? -1;
226 3
        if ($code != GeneralResponse\ResponseHeader::RESPONSECODE_OK) {
227 1
            throw new DynadotApiException($resultData->DomainInfoHeader?->Error ?: 'Unknown error. Response code: ' . $code);
228
        }
229
230 2
        $this->log(LogLevel::DEBUG, 'Returning domain info');
231
232
        // Here we know our API call was successful, return the domain info.
233 2
        return $resultData->DomainInfoContent->Domain;
234
    }
235
236
    /**
237
     * Log a message to our logger if we have any.
238
     *
239
     * @param string $level
240
     * @param string $message
241
     */
242 27
    protected function log(string $level, string $message): void
243
    {
244 27
        if ($this->logger instanceof LoggerInterface) {
245 1
            $this->logger->log($level, $message);
246
        }
247
    }
248
249
    /**
250
     * Performs the actual API call (internal method)
251
     *
252
     * @param array<int|string,mixed> $requestData
253
     *
254
     * @return \Psr\Http\Message\StreamInterface
255
     * @throws \GuzzleHttp\Exception\GuzzleException
256
     * @throws \Level23\Dynadot\Exception\ApiHttpCallFailedException
257
     */
258 26
    protected function performRawApiCall(array $requestData): StreamInterface
259
    {
260 26
        $this->log(LogLevel::DEBUG, 'Perform raw call: ' . var_export($requestData, true));
261
262
        // transform the request data into a valid query string
263 26
        $requestDataHttp = http_build_query($requestData);
264
265
        // spawn Guzzle
266 26
        $client = new Client($this->guzzleOptions);
267
268 26
        $url = self::DYNADOT_API_URL .
269 26
            '?key=' . urlencode($this->getApiKey()) .
270 26
            ($requestDataHttp ? '&' . $requestDataHttp : '');
271
272 26
        $this->log(LogLevel::DEBUG, 'Start new guzzle request with URL: ' . $url);
273
274
        // start a request without an API key and optionally our request data
275 26
        $response = $client->request('GET', $url);
276
277 26
        $this->log(LogLevel::DEBUG, 'Received response with status code ' . $response->getStatusCode());
278
279
        // if we did not get an HTTP 200 response, our HTTP call failed (which is different from a failed API call)
280 26
        if ($response->getStatusCode() != 200) {
281 1
            $this->log(LogLevel::ALERT, 'Received wrong HTTP status code: ' . $response->getStatusCode());
282
            // not ok
283 1
            throw new ApiHttpCallFailedException(
284 1
                'HTTP API call failed, expected 200 status, got ' . $response->getStatusCode()
285 1
            );
286
        }
287
288
        // Return the response body (which is a stream coming from Guzzle).
289
        // Sabre XML semi-handles streams (it will just get the contents of the stream using stream_get_contents), so
290
        // this should work! ;)
291 25
        return $response->getBody();
292
    }
293
294
    /**
295
     * @return string
296
     */
297 27
    public function getApiKey(): string
298
    {
299 27
        return $this->apiKey;
300
    }
301
302
    /**
303
     * @param string $apiKey
304
     */
305 28
    public function setApiKey(string $apiKey): void
306
    {
307 28
        $this->apiKey = $apiKey;
308
    }
309
310
    /**
311
     * Set nameservers for a domain (max 13). An exception will be thrown in case of an error.
312
     *
313
     * @param string            $domain The domain where to set the nameservers for.
314
     * @param array<int,string> $nameservers
315
     *
316
     * @throws \GuzzleHttp\Exception\GuzzleException
317
     * @throws \Level23\Dynadot\Exception\ApiHttpCallFailedException
318
     * @throws \Level23\Dynadot\Exception\ApiLimitationExceededException
319
     * @throws \Level23\Dynadot\Exception\DynadotApiException
320
     * @throws \Sabre\Xml\ParseException
321
     */
322 6
    public function setNameserversForDomain(string $domain, array $nameservers): void
323
    {
324 6
        $this->log(LogLevel::DEBUG, 'Set ' . sizeof($nameservers) . ' nameservers for domain ' . $domain);
325 6
        $requestData = [
326 6
            'command' => 'set_ns',
327 6
            'domain'  => $domain,
328 6
        ];
329
330 6
        if (sizeof($nameservers) > 13) {
331
            // the index starts at 0, so we should check if the index is greater than 12 (which is 13 nameservers)
332 1
            throw new ApiLimitationExceededException(
333 1
                'Can not define more than 13 nameservers through the API'
334 1
            );
335
        }
336
337 5
        $idx = 0;
338
        // check if there are more than 13 nameservers defined
339 5
        foreach ($nameservers as $nameserver) {
340 5
            $requestData['ns' . $idx++] = $nameserver;
341
        }
342
343
        // perform the API call
344 5
        $response = $this->performRawApiCall($requestData);
345
346 5
        $this->log(LogLevel::DEBUG, 'API call executed, parsing response...');
347
348
        // start parsing XML data using Sabre
349 5
        $sabreService = new Service();
350
351
        // set mapping
352 5
        $sabreService->elementMap = [
353 5
            '{}ResponseCode'              => $this->intDeserializer,
354 5
            '{}SuccessCode'              => $this->intDeserializer,
355 5
        ];
356
357
        // map certain values to objects
358 5
        $sabreService->mapValueObject('{}SetNsResponse', SetNsResponse\SetNsResponse::class);
359 5
        $sabreService->mapValueObject('{}SetNsHeader', SetNsResponse\SetNsHeader::class);
360 5
        $sabreService->mapValueObject('{}Response', GeneralResponse\Response::class);
361 5
        $sabreService->mapValueObject('{}ResponseHeader', GeneralResponse\ResponseHeader::class);
362
363
        // parse the data
364 5
        $resultData = $sabreService->parse($response->getContents());
365
366
        // General error, like an incorrect api key
367 4
        if ($resultData instanceof GeneralResponse\Response) {
368 1
            $code = $resultData->ResponseHeader->ResponseCode;
369 1
            if ($code != GeneralResponse\ResponseHeader::RESPONSECODE_OK) {
370 1
                throw new DynadotApiException($resultData->ResponseHeader->Error);
371
            }
372
        }
373
374 3
        if (!$resultData instanceof SetNsResponse\SetNsResponse) {
375 1
            throw new DynadotApiException('We failed to parse the response');
376
        }
377
378
        /**
379
         * Check if the API call was successful. If not, return the error
380
         */
381 2
        $code = max($resultData->SetNsHeader->SuccessCode, $resultData->SetNsHeader->ResponseCode);
382 2
        if ($code != SetNsResponse\SetNsHeader::SUCCESSCODE_OK) {
383 1
            throw new DynadotApiException($resultData->SetNsHeader->Error);
384
        }
385
386 1
        $this->log(LogLevel::DEBUG, 'Received correct response. Everything is ok!');
387
    }
388
389
    /**
390
     * List all domains in the account. We will return an array with Domain objects
391
     *
392
     * @return DomainResponse\Domain[]
393
     * @throws \GuzzleHttp\Exception\GuzzleException
394
     * @throws \Level23\Dynadot\Exception\ApiHttpCallFailedException
395
     * @throws \Level23\Dynadot\Exception\DynadotApiException
396
     * @throws \Sabre\Xml\ParseException
397
     */
398 5
    public function getDomainList(): array
399
    {
400 5
        $this->log(LogLevel::DEBUG, 'Start retrieving all domains');
401 5
        $requestData = [
402 5
            'command' => 'list_domain',
403 5
        ];
404
405
        // perform the API call
406 5
        $response = $this->performRawApiCall($requestData);
407
408 5
        $this->log(LogLevel::DEBUG, 'Start parsing response XML');
409
410
        // start parsing XML data using Sabre
411 5
        $sabreService = new Service();
412
413
        // set mapping
414 5
        $sabreService->elementMap = [
415 5
            '{}NameServers'          => function (Reader $reader) {
416
417
                $nameservers = [];
418
                $id          = '';
419
420
                $children = (array)$reader->parseInnerTree();
421
422
                foreach ($children as $child) {
423
                    if ($child['name'] == '{}ServerId') {
424
                        $id = $child['value'];
425
                    } elseif ($child['name'] == '{}ServerName') {
426
                        if (!empty($id) && !empty($child['value'])) {
427
                            $nameserver             = new DomainResponse\NameServer();
428
                            $nameserver->ServerId   = $id;
429
                            $nameserver->ServerName = $child['value'];
430
431
                            $nameservers[] = $nameserver;
432
                        }
433
                        $id = null;
434
                    }
435
                }
436
437
                return $nameservers;
438 5
            },
439 5
            '{}DomainInfoList'       => function (Reader $reader) {
440 1
                $domains = [];
441
442 1
                $tree = (array)$reader->parseInnerTree();
443
444 1
                foreach ($tree as $item) {
445 1
                    foreach ($item['value'] as $domain) {
446 1
                        $domains[] = $domain['value'];
447
                    }
448
                }
449
450 1
                return $domains;
451 5
            },
452 5
            '{}Registrant'           => $this->contactIdDeserializer,
453 5
            '{}Admin'                => $this->contactIdDeserializer,
454 5
            '{}Technical'            => $this->contactIdDeserializer,
455 5
            '{}Billing'              => $this->contactIdDeserializer,
456 5
            '{}isForSale'            => $this->booleanDeserializer,
457 5
            '{}Hold'                 => $this->booleanDeserializer,
458 5
            '{}RegistrantUnverified' => $this->booleanDeserializer,
459 5
            '{}UdrpLocked'           => $this->booleanDeserializer,
460 5
            '{}Disabled'             => $this->booleanDeserializer,
461 5
            '{}Locked'               => $this->booleanDeserializer,
462 5
            '{}WithAds'              => $this->booleanDeserializer,
463 5
            '{}ResponseCode'         => $this->intDeserializer,
464 5
        ];
465
466
        // map certain values to objects
467 5
        $sabreService->mapValueObject('{}ListDomainInfoResponse', ListDomainInfoResponse\ListDomainInfoResponse::class);
468 5
        $sabreService->mapValueObject('{}ListDomainInfoHeader', ListDomainInfoResponse\ListDomainInfoHeader::class);
469 5
        $sabreService->mapValueObject('{}ListDomainInfoContent', ListDomainInfoResponse\ListDomainInfoContent::class);
470 5
        $sabreService->mapValueObject('{}Domain', DomainResponse\Domain::class);
471 5
        $sabreService->mapValueObject('{}NameServerSettings', DomainResponse\NameServerSettings::class);
472 5
        $sabreService->mapValueObject('{}Whois', DomainResponse\Whois::class);
473 5
        $sabreService->mapValueObject('{}Folder', DomainResponse\Folder::class);
474 5
        $sabreService->mapValueObject('{}Response', GeneralResponse\Response::class);
475 5
        $sabreService->mapValueObject('{}ResponseHeader', GeneralResponse\ResponseHeader::class);
476
477
        // parse the data
478 5
        $resultData = $sabreService->parse($response->getContents());
479
480
        // General error, like an incorrect api key
481 4
        if ($resultData instanceof GeneralResponse\Response) {
482 1
            $code = $resultData->ResponseHeader->ResponseCode;
483 1
            if ($code != GeneralResponse\ResponseHeader::RESPONSECODE_OK) {
484 1
                throw new DynadotApiException($resultData->ResponseHeader->Error);
485
            }
486
        }
487
488 3
        if (!$resultData instanceof ListDomainInfoResponse\ListDomainInfoResponse) {
489 1
            throw new DynadotApiException('We failed to parse the response');
490
        }
491
492
        /**
493
         * Check if the API call was successful. If not, return the error
494
         */
495 2
        $code = $resultData->ListDomainInfoHeader->ResponseCode;
496 2
        if ($code != ListDomainInfoResponse\ListDomainInfoHeader::RESPONSECODE_OK) {
497 1
            throw new DynadotApiException($resultData->ListDomainInfoHeader->Error);
498
        }
499
500 1
        return $resultData->ListDomainInfoContent->DomainInfoList;
501
    }
502
503
    /**
504
     * Get contact information for a specific contact ID
505
     *
506
     * @param int $contactId The contact ID we should request
507
     *
508
     * @return GetContactResponse\Contact
509
     * @throws \GuzzleHttp\Exception\GuzzleException
510
     * @throws \Level23\Dynadot\Exception\ApiHttpCallFailedException
511
     * @throws \Level23\Dynadot\Exception\DynadotApiException
512
     * @throws \Sabre\Xml\ParseException
513
     */
514 5
    public function getContactInfo(int $contactId): GetContactResponse\Contact
515
    {
516 5
        $this->log(LogLevel::DEBUG, 'Fetch contact details for id ' . $contactId);
517
518 5
        $requestData = [
519 5
            'command'    => 'get_contact',
520 5
            'contact_id' => $contactId,
521 5
        ];
522
523
        // perform the API call
524 5
        $response = $this->performRawApiCall($requestData);
525
526 5
        $this->log(LogLevel::DEBUG, 'Start parsing result');
527
528
        // start parsing XML data using Sabre
529 5
        $sabreService = new Service();
530
531
        // set mapping
532 5
        $sabreService->elementMap = [
533 5
            '{}ResponseCode' => $this->intDeserializer,
534 5
        ];
535
536
        // map certain values to objects
537 5
        $sabreService->mapValueObject('{}GetContactResponse', GetContactResponse\GetContactResponse::class);
538 5
        $sabreService->mapValueObject('{}GetContactHeader', GetContactResponse\GetContactHeader::class);
539 5
        $sabreService->mapValueObject('{}GetContactContent', GetContactResponse\GetContactContent::class);
540 5
        $sabreService->mapValueObject('{}Contact', GetContactResponse\Contact::class);
541 5
        $sabreService->mapValueObject('{}Response', GeneralResponse\Response::class);
542 5
        $sabreService->mapValueObject('{}ResponseHeader', GeneralResponse\ResponseHeader::class);
543
544
        // parse the data
545 5
        $resultData = $sabreService->parse($response->getContents());
546
547
        // General error, like an incorrect api key
548 4
        if ($resultData instanceof GeneralResponse\Response) {
549 1
            $code = $resultData->ResponseHeader->ResponseCode;
550 1
            if ($code != GeneralResponse\ResponseHeader::RESPONSECODE_OK) {
551 1
                throw new DynadotApiException($resultData->ResponseHeader->Error);
552
            }
553
        }
554
555 3
        if (!$resultData instanceof GetContactResponse\GetContactResponse) {
556 1
            throw new DynadotApiException('We failed to parse the response');
557
        }
558
559
        /**
560
         * Check if the API call was successful. If not, return the error
561
         */
562 2
        $code = $resultData->GetContactHeader->ResponseCode;
563 2
        if ($code != GetContactResponse\GetContactHeader::RESPONSECODE_OK) {
564 1
            throw new DynadotApiException($resultData->GetContactHeader->Error);
565
        }
566
567 1
        return $resultData->GetContactContent->Contact;
568
    }
569
570
    /**
571
     * @throws \Level23\Dynadot\Exception\DynadotApiException
572
     * @throws \Sabre\Xml\ParseException
573
     * @throws \GuzzleHttp\Exception\GuzzleException
574
     * @throws \Level23\Dynadot\Exception\ApiHttpCallFailedException
575
     */
576 4
    public function setRenewOption(string $domain, string $renewOption): bool
577
    {
578 4
        $this->log(LogLevel::INFO, 'Set auto renew for: ' . $domain . ' to: ' . $renewOption);
579
580 4
        $requestData = [
581 4
            'command'      => 'set_renew_option',
582 4
            'domain'       => $domain,
583 4
            'renew_option' => $renewOption,
584 4
        ];
585
586
        // perform the API call
587 4
        $response = $this->performRawApiCall($requestData);
588
589 4
        $this->log(LogLevel::DEBUG, 'Start parsing result');
590
591
        // start parsing XML data using Sabre
592 4
        $sabreService = new Service();
593
594
        // set mapping
595 4
        $sabreService->elementMap = [
596 4
            '{}ResponseCode'              => $this->intDeserializer,
597 4
            '{}SuccessCode'              => $this->intDeserializer,
598 4
        ];
599
600
        // map certain values to objects
601 4
        $sabreService->mapValueObject('{}SetRenewOptionResponse', SetRenewOptionResponse::class);
602 4
        $sabreService->mapValueObject('{}SetRenewOptionHeader', SetRenewOptionHeader::class);
603 4
        $sabreService->mapValueObject('{}Response', GeneralResponse\Response::class);
604 4
        $sabreService->mapValueObject('{}ResponseHeader', GeneralResponse\ResponseHeader::class);
605
606
        // parse the data
607 4
        $resultData = $sabreService->parse($response->getContents());
608
609
        // General error, like an incorrect api key
610 4
        if ($resultData instanceof GeneralResponse\Response) {
611 1
            $code = $resultData->ResponseHeader->ResponseCode;
612 1
            if ($code != GeneralResponse\ResponseHeader::RESPONSECODE_OK) {
613 1
                throw new DynadotApiException($resultData->ResponseHeader->Error);
614
            }
615
        }
616
617 3
        if (!$resultData instanceof SetRenewOptionResponse) {
618 1
            throw new DynadotApiException('We failed to parse the response');
619
        }
620
621 2
        $code = (int)$resultData->SetRenewOptionHeader->SuccessCode;
622 2
        if ($code != SetRenewOptionHeader::SUCCESSCODE_OK) {
623 1
            throw new DynadotApiException((string)$resultData->SetRenewOptionHeader->Error);
624
        }
625
626 1
        return true;
627
    }
628
}
629