ResolverAbstract::getTXTRecords()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 3
rs 10
1
<?php
2
3
namespace RemotelyLiving\PHPDNS\Resolvers;
4
5
use RemotelyLiving\PHPDNS\Entities\DNSRecord;
6
use RemotelyLiving\PHPDNS\Entities\DNSRecordCollection;
7
use RemotelyLiving\PHPDNS\Entities\Interfaces\DNSRecordInterface;
8
use RemotelyLiving\PHPDNS\Entities\DNSRecordType;
9
use RemotelyLiving\PHPDNS\Entities\Hostname;
10
use RemotelyLiving\PHPDNS\Exceptions\InvalidArgumentException;
11
use RemotelyLiving\PHPDNS\Mappers\MapperInterface;
12
use RemotelyLiving\PHPDNS\Observability\Events\DNSQueried;
13
use RemotelyLiving\PHPDNS\Observability\Events\DNSQueryFailed;
14
use RemotelyLiving\PHPDNS\Observability\Events\DNSQueryProfiled;
15
use RemotelyLiving\PHPDNS\Observability\Traits\Dispatcher;
16
use RemotelyLiving\PHPDNS\Observability\Traits\Logger;
17
use RemotelyLiving\PHPDNS\Observability\Traits\Profileable;
18
use RemotelyLiving\PHPDNS\Resolvers\Exceptions\QueryFailure;
19
use RemotelyLiving\PHPDNS\Resolvers\Interfaces\ObservableResolver;
20
21
use function array_map;
22
use function array_pop;
23
use function explode;
24
use function get_class;
25
use function json_encode;
26
27
abstract class ResolverAbstract implements ObservableResolver
28
{
29
    use Logger;
30
    use Dispatcher;
31
    use Profileable;
32
33
    private string $name;
34
    /**
35
     * @var string
36
     */
37
    private const EVENT = 'event';
38
39
    public function getName(): string
40
    {
41
        if (!isset($this->name)) {
42
            $explodedClass = explode('\\', $this::class);
43
            $this->name = (string) array_pop($explodedClass);
44
        }
45
46
        return $this->name;
47
    }
48
49
    public function getARecords(string $hostname): DNSRecordCollection
50
    {
51
        return $this->getRecords($hostname, (string)DNSRecordType::createA());
52
    }
53
54
    public function getAAAARecords(string $hostname): DNSRecordCollection
55
    {
56
        return $this->getRecords($hostname, (string)DNSRecordType::createAAAA());
57
    }
58
59
    public function getCNAMERecords(string $hostname): DNSRecordCollection
60
    {
61
        return $this->getRecords($hostname, (string)DNSRecordType::createCNAME());
62
    }
63
64
    public function getTXTRecords(string $hostname): DNSRecordCollection
65
    {
66
        return $this->getRecords($hostname, (string)DNSRecordType::createTXT());
67
    }
68
69
    public function getMXRecords(string $hostname): DNSRecordCollection
70
    {
71
        return $this->getRecords($hostname, (string)DNSRecordType::createMX());
72
    }
73
74
    public function recordTypeExists(string $hostname, string $recordType): bool
75
    {
76
        return !$this->getRecords($hostname, $recordType)->isEmpty();
77
    }
78
79
    public function hasRecord(DNSRecordInterface $record): bool
80
    {
81
        return $this->getRecords((string)$record->getHostname(), (string)$record->getType())
82
            ->has($record);
83
    }
84
85
    /**
86
     * @throws \RemotelyLiving\PHPDNS\Resolvers\Exceptions\QueryFailure
87
     */
88
    public function getRecords(string $hostname, string $recordType = null): DNSRecordCollection
89
    {
90
        $recordType = DNSRecordType::createFromString($recordType ?? 'ANY');
91
        $hostname = Hostname::createFromString($hostname);
92
93
        $profile = $this->createProfile("{$this->getName()}:{$hostname}:{$recordType}");
94
        $profile->startTransaction();
95
96
        try {
97
            $result = ($recordType->equals(DNSRecordType::createANY()))
98
                ? $this->doQuery($hostname, $recordType)
99
                : $this->doQuery($hostname, $recordType)->filteredByType($recordType);
100
        } catch (QueryFailure $e) {
101
            $dnsQueryFailureEvent = new DNSQueryFailed($this, $hostname, $recordType, $e);
102
            $this->dispatch($dnsQueryFailureEvent);
103
            $this->getLogger()->error(
104
                'DNS query failed',
105
                [self::EVENT => json_encode($dnsQueryFailureEvent, JSON_THROW_ON_ERROR), 'exception' => $e]
106
            );
107
108
            throw $e;
109
        } finally {
110
            $profile->endTransaction();
111
            $profile->samplePeakMemoryUsage();
112
            $dnsQueryProfiledEvent = new DNSQueryProfiled($profile);
113
            $this->dispatch($dnsQueryProfiledEvent);
114
            $this->getLogger()->info('DNS query profiled', [self::EVENT => json_encode($dnsQueryProfiledEvent)]);
115
        }
116
117
        $dnsQueriedEvent = new DNSQueried($this, $hostname, $recordType, $result);
118
        $this->dispatch($dnsQueriedEvent);
119
        $this->getLogger()->info('DNS queried', [self::EVENT => json_encode($dnsQueriedEvent, JSON_THROW_ON_ERROR)]);
120
        return $result;
121
    }
122
123
    public function mapResults(MapperInterface $mapper, array $results): DNSRecordCollection
124
    {
125
        $collection = new DNSRecordCollection();
126
        array_map(function (array $fields) use (&$collection, $mapper) {
127
            try {
128
                $collection[] = $mapper->mapFields($fields)->toDNSRecord();
129
            } catch (InvalidArgumentException) {
130
                $this->getLogger()->warning('Invalid fields passed to mapper', $fields);
131
            }
132
        }, $results);
133
134
        return $collection;
135
    }
136
137
    /**
138
     * @throws \RemotelyLiving\PHPDNS\Resolvers\Exceptions\QueryFailure
139
     */
140
    abstract protected function doQuery(Hostname $hostname, DNSRecordType $recordType): DNSRecordCollection;
141
}
142